ip_proxy.c revision 145522
1145522Sdarrenr/* $FreeBSD: head/sys/contrib/ipfilter/netinet/ip_proxy.c 145522 2005-04-25 18:43:14Z darrenr $ */ 2145522Sdarrenr 353642Sguido/* 4145522Sdarrenr * Copyright (C) 1997-2003 by Darren Reed. 553642Sguido * 680482Sdarrenr * See the IPFILTER.LICENCE file for details on licencing. 753642Sguido */ 8145522Sdarrenr#if defined(KERNEL) || defined(_KERNEL) 9145522Sdarrenr# undef KERNEL 10145522Sdarrenr# undef _KERNEL 11145522Sdarrenr# define KERNEL 1 12145522Sdarrenr# define _KERNEL 1 1353642Sguido#endif 1453642Sguido#include <sys/errno.h> 1553642Sguido#include <sys/types.h> 1653642Sguido#include <sys/param.h> 1753642Sguido#include <sys/time.h> 1853642Sguido#include <sys/file.h> 1953642Sguido#include <sys/fcntl.h> 20145522Sdarrenr#if !defined(_KERNEL) && !defined(__KERNEL__) 2153642Sguido# include <stdio.h> 2253642Sguido# include <string.h> 2353642Sguido# include <stdlib.h> 24145522Sdarrenr# include <ctype.h> 25145522Sdarrenr# define _KERNEL 26145522Sdarrenr# ifdef __OpenBSD__ 27145522Sdarrenrstruct file; 28145522Sdarrenr# endif 29145522Sdarrenr# include <sys/uio.h> 30145522Sdarrenr# undef _KERNEL 3153642Sguido#endif 32145522Sdarrenr#if !defined(linux) 3353642Sguido# include <sys/protosw.h> 3453642Sguido#endif 3553642Sguido#include <sys/socket.h> 3653642Sguido#if defined(_KERNEL) 37145522Sdarrenr# if !defined(__NetBSD__) && !defined(sun) && !defined(__osf__) && \ 38145522Sdarrenr !defined(__OpenBSD__) && !defined(__hpux) && !defined(__sgi) 39145522Sdarrenr# include <sys/ctype.h> 4053642Sguido# endif 41145522Sdarrenr# include <sys/systm.h> 42145522Sdarrenr# if !defined(__SVR4) && !defined(__svr4__) 4353642Sguido# include <sys/mbuf.h> 4453642Sguido# endif 45145522Sdarrenr#endif 46145522Sdarrenr#if defined(_KERNEL) && (__FreeBSD_version >= 220000) 47145522Sdarrenr# include <sys/filio.h> 48145522Sdarrenr# include <sys/fcntl.h> 49145522Sdarrenr# if (__FreeBSD_version >= 300000) && !defined(IPFILTER_LKM) 50145522Sdarrenr# include "opt_ipfilter.h" 51145522Sdarrenr# endif 5253642Sguido#else 53145522Sdarrenr# include <sys/ioctl.h> 54145522Sdarrenr#endif 55145522Sdarrenr#if defined(__SVR4) || defined(__svr4__) 5653642Sguido# include <sys/byteorder.h> 5753642Sguido# ifdef _KERNEL 5853642Sguido# include <sys/dditypes.h> 5953642Sguido# endif 6053642Sguido# include <sys/stream.h> 6153642Sguido# include <sys/kmem.h> 6253642Sguido#endif 6353642Sguido#if __FreeBSD__ > 2 6453642Sguido# include <sys/queue.h> 6553642Sguido#endif 6653642Sguido#include <net/if.h> 6753642Sguido#ifdef sun 6853642Sguido# include <net/af.h> 6953642Sguido#endif 7053642Sguido#include <net/route.h> 7153642Sguido#include <netinet/in.h> 7253642Sguido#include <netinet/in_systm.h> 7353642Sguido#include <netinet/ip.h> 7453642Sguido#ifndef linux 7553642Sguido# include <netinet/ip_var.h> 7653642Sguido#endif 7753642Sguido#include <netinet/tcp.h> 7853642Sguido#include <netinet/udp.h> 7953642Sguido#include <netinet/ip_icmp.h> 8053642Sguido#include "netinet/ip_compat.h" 8153642Sguido#include <netinet/tcpip.h> 8253642Sguido#include "netinet/ip_fil.h" 8353642Sguido#include "netinet/ip_nat.h" 8453642Sguido#include "netinet/ip_state.h" 8592685Sdarrenr#include "netinet/ip_proxy.h" 8653642Sguido#if (__FreeBSD_version >= 300000) 8753642Sguido# include <sys/malloc.h> 8853642Sguido#endif 8953642Sguido 90145522Sdarrenr#include "netinet/ip_ftp_pxy.c" 91145522Sdarrenr#include "netinet/ip_rcmd_pxy.c" 92145522Sdarrenr# include "netinet/ip_pptp_pxy.c" 93145522Sdarrenr#if defined(_KERNEL) 94145522Sdarrenr# include "netinet/ip_irc_pxy.c" 95145522Sdarrenr# include "netinet/ip_raudio_pxy.c" 96145522Sdarrenr# include "netinet/ip_h323_pxy.c" 97145522Sdarrenr# ifdef IPFILTER_PRO 98145522Sdarrenr# include "netinet/ip_msnrpc_pxy.c" 99145522Sdarrenr# endif 100145522Sdarrenr# include "netinet/ip_netbios_pxy.c" 10180482Sdarrenr#endif 102145522Sdarrenr#include "netinet/ip_ipsec_pxy.c" 103145522Sdarrenr#include "netinet/ip_rpcb_pxy.c" 10453642Sguido 105145522Sdarrenr/* END OF INCLUDES */ 106145522Sdarrenr 107145522Sdarrenr#if !defined(lint) 108145522Sdarrenrstatic const char rcsid[] = "@(#)Id: ip_proxy.c,v 2.62.2.12 2005/03/03 14:28:24 darrenr Exp"; 10992685Sdarrenr#endif 11080482Sdarrenr 11153642Sguidostatic int appr_fixseqack __P((fr_info_t *, ip_t *, ap_session_t *, int )); 11253642Sguido 11353642Sguido#define AP_SESS_SIZE 53 11453642Sguido 11592685Sdarrenr#if defined(_KERNEL) 116145522Sdarrenrint ipf_proxy_debug = 0; 117145522Sdarrenr#else 118145522Sdarrenrint ipf_proxy_debug = 2; 11953642Sguido#endif 12053642Sguidoap_session_t *ap_sess_tab[AP_SESS_SIZE]; 12153642Sguidoap_session_t *ap_sess_list = NULL; 12260855Sdarrenraproxy_t *ap_proxylist = NULL; 12353642Sguidoaproxy_t ap_proxies[] = { 12453642Sguido#ifdef IPF_FTP_PROXY 125145522Sdarrenr { NULL, "ftp", (char)IPPROTO_TCP, 0, 0, ippr_ftp_init, ippr_ftp_fini, 12692685Sdarrenr ippr_ftp_new, NULL, ippr_ftp_in, ippr_ftp_out, NULL }, 12753642Sguido#endif 128145522Sdarrenr#ifdef IPF_IRC_PROXY 129145522Sdarrenr { NULL, "irc", (char)IPPROTO_TCP, 0, 0, ippr_irc_init, ippr_irc_fini, 130145522Sdarrenr ippr_irc_new, NULL, NULL, ippr_irc_out, NULL, NULL }, 131145522Sdarrenr#endif 13253642Sguido#ifdef IPF_RCMD_PROXY 133145522Sdarrenr { NULL, "rcmd", (char)IPPROTO_TCP, 0, 0, ippr_rcmd_init, ippr_rcmd_fini, 134145522Sdarrenr ippr_rcmd_new, NULL, ippr_rcmd_in, ippr_rcmd_out, NULL, NULL }, 13553642Sguido#endif 13653642Sguido#ifdef IPF_RAUDIO_PROXY 137145522Sdarrenr { NULL, "raudio", (char)IPPROTO_TCP, 0, 0, ippr_raudio_init, ippr_raudio_fini, 138145522Sdarrenr ippr_raudio_new, NULL, ippr_raudio_in, ippr_raudio_out, NULL, NULL }, 13953642Sguido#endif 140145522Sdarrenr#ifdef IPF_MSNRPC_PROXY 141145522Sdarrenr { NULL, "msnrpc", (char)IPPROTO_TCP, 0, 0, ippr_msnrpc_init, ippr_msnrpc_fini, 142145522Sdarrenr ippr_msnrpc_new, NULL, ippr_msnrpc_in, ippr_msnrpc_out, NULL, NULL }, 14392685Sdarrenr#endif 14492685Sdarrenr#ifdef IPF_NETBIOS_PROXY 145145522Sdarrenr { NULL, "netbios", (char)IPPROTO_UDP, 0, 0, ippr_netbios_init, ippr_netbios_fini, 146145522Sdarrenr NULL, NULL, NULL, ippr_netbios_out, NULL, NULL }, 14792685Sdarrenr#endif 148145522Sdarrenr#ifdef IPF_IPSEC_PROXY 149145522Sdarrenr { NULL, "ipsec", (char)IPPROTO_UDP, 0, 0, 150145522Sdarrenr ippr_ipsec_init, ippr_ipsec_fini, ippr_ipsec_new, ippr_ipsec_del, 151145522Sdarrenr ippr_ipsec_inout, ippr_ipsec_inout, ippr_ipsec_match, NULL }, 152145522Sdarrenr#endif 153145522Sdarrenr#ifdef IPF_PPTP_PROXY 154145522Sdarrenr { NULL, "pptp", (char)IPPROTO_TCP, 0, 0, 155145522Sdarrenr ippr_pptp_init, ippr_pptp_fini, ippr_pptp_new, ippr_pptp_del, 156145522Sdarrenr ippr_pptp_inout, ippr_pptp_inout, NULL, NULL }, 157145522Sdarrenr#endif 15892685Sdarrenr#ifdef IPF_H323_PROXY 159145522Sdarrenr { NULL, "h323", (char)IPPROTO_TCP, 0, 0, ippr_h323_init, ippr_h323_fini, 160145522Sdarrenr ippr_h323_new, ippr_h323_del, ippr_h323_in, NULL, NULL }, 161145522Sdarrenr { NULL, "h245", (char)IPPROTO_TCP, 0, 0, NULL, NULL, 162145522Sdarrenr ippr_h245_new, NULL, NULL, ippr_h245_out, NULL }, 163145522Sdarrenr#endif 164145522Sdarrenr#ifdef IPF_RPCB_PROXY 165145522Sdarrenr# if 0 166145522Sdarrenr { NULL, "rpcbt", (char)IPPROTO_TCP, 0, 0, 167145522Sdarrenr ippr_rpcb_init, ippr_rpcb_fini, ippr_rpcb_new, ippr_rpcb_del, 168145522Sdarrenr ippr_rpcb_in, ippr_rpcb_out, NULL, NULL }, 169145522Sdarrenr# endif 170145522Sdarrenr { NULL, "rpcbu", (char)IPPROTO_UDP, 0, 0, 171145522Sdarrenr ippr_rpcb_init, ippr_rpcb_fini, ippr_rpcb_new, ippr_rpcb_del, 172145522Sdarrenr ippr_rpcb_in, ippr_rpcb_out, NULL, NULL }, 173145522Sdarrenr#endif 174145522Sdarrenr { NULL, "", '\0', 0, 0, NULL, NULL, NULL, NULL } 17553642Sguido}; 17653642Sguido 17792685Sdarrenr/* 17892685Sdarrenr * Dynamically add a new kernel proxy. Ensure that it is unique in the 17992685Sdarrenr * collection compiled in and dynamically added. 18092685Sdarrenr */ 18160855Sdarrenrint appr_add(ap) 18260855Sdarrenraproxy_t *ap; 18360855Sdarrenr{ 18460855Sdarrenr aproxy_t *a; 18560855Sdarrenr 18660855Sdarrenr for (a = ap_proxies; a->apr_p; a++) 18760855Sdarrenr if ((a->apr_p == ap->apr_p) && 18860855Sdarrenr !strncmp(a->apr_label, ap->apr_label, 189145522Sdarrenr sizeof(ap->apr_label))) { 190145522Sdarrenr if (ipf_proxy_debug > 1) 191145522Sdarrenr printf("appr_add: %s/%d already present (B)\n", 192145522Sdarrenr a->apr_label, a->apr_p); 19360855Sdarrenr return -1; 194145522Sdarrenr } 19560855Sdarrenr 196145522Sdarrenr for (a = ap_proxylist; a->apr_p; a = a->apr_next) 19760855Sdarrenr if ((a->apr_p == ap->apr_p) && 19860855Sdarrenr !strncmp(a->apr_label, ap->apr_label, 199145522Sdarrenr sizeof(ap->apr_label))) { 200145522Sdarrenr if (ipf_proxy_debug > 1) 201145522Sdarrenr printf("appr_add: %s/%d already present (D)\n", 202145522Sdarrenr a->apr_label, a->apr_p); 20360855Sdarrenr return -1; 204145522Sdarrenr } 20560855Sdarrenr ap->apr_next = ap_proxylist; 20660855Sdarrenr ap_proxylist = ap; 207145522Sdarrenr if (ap->apr_init != NULL) 208145522Sdarrenr return (*ap->apr_init)(); 209145522Sdarrenr return 0; 21060855Sdarrenr} 21160855Sdarrenr 21260855Sdarrenr 21392685Sdarrenr/* 214145522Sdarrenr * Check to see if the proxy this control request has come through for 215145522Sdarrenr * exists, and if it does and it has a control function then invoke that 216145522Sdarrenr * control function. 217145522Sdarrenr */ 218145522Sdarrenrint appr_ctl(ctl) 219145522Sdarrenrap_ctl_t *ctl; 220145522Sdarrenr{ 221145522Sdarrenr aproxy_t *a; 222145522Sdarrenr int error; 223145522Sdarrenr 224145522Sdarrenr a = appr_lookup(ctl->apc_p, ctl->apc_label); 225145522Sdarrenr if (a == NULL) { 226145522Sdarrenr if (ipf_proxy_debug > 1) 227145522Sdarrenr printf("appr_ctl: can't find %s/%d\n", 228145522Sdarrenr ctl->apc_label, ctl->apc_p); 229145522Sdarrenr error = ESRCH; 230145522Sdarrenr } else if (a->apr_ctl == NULL) { 231145522Sdarrenr if (ipf_proxy_debug > 1) 232145522Sdarrenr printf("appr_ctl: no ctl function for %s/%d\n", 233145522Sdarrenr ctl->apc_label, ctl->apc_p); 234145522Sdarrenr error = ENXIO; 235145522Sdarrenr } else { 236145522Sdarrenr error = (*a->apr_ctl)(a, ctl); 237145522Sdarrenr if ((error != 0) && (ipf_proxy_debug > 1)) 238145522Sdarrenr printf("appr_ctl: %s/%d ctl error %d\n", 239145522Sdarrenr a->apr_label, a->apr_p, error); 240145522Sdarrenr } 241145522Sdarrenr return error; 242145522Sdarrenr} 243145522Sdarrenr 244145522Sdarrenr 245145522Sdarrenr/* 24692685Sdarrenr * Delete a proxy that has been added dynamically from those available. 24792685Sdarrenr * If it is in use, return 1 (do not destroy NOW), not in use 0 or -1 24892685Sdarrenr * if it cannot be matched. 24992685Sdarrenr */ 25060855Sdarrenrint appr_del(ap) 25160855Sdarrenraproxy_t *ap; 25260855Sdarrenr{ 25360855Sdarrenr aproxy_t *a, **app; 25460855Sdarrenr 255145522Sdarrenr for (app = &ap_proxylist; ((a = *app) != NULL); app = &a->apr_next) 25660855Sdarrenr if (a == ap) { 25792685Sdarrenr a->apr_flags |= APR_DELETE; 25892685Sdarrenr *app = a->apr_next; 259145522Sdarrenr if (ap->apr_ref != 0) { 260145522Sdarrenr if (ipf_proxy_debug > 2) 261145522Sdarrenr printf("appr_del: orphaning %s/%d\n", 262145522Sdarrenr ap->apr_label, ap->apr_p); 26360855Sdarrenr return 1; 264145522Sdarrenr } 26560855Sdarrenr return 0; 26660855Sdarrenr } 267145522Sdarrenr if (ipf_proxy_debug > 1) 268145522Sdarrenr printf("appr_del: proxy %lx not found\n", (u_long)ap); 26960855Sdarrenr return -1; 27060855Sdarrenr} 27160855Sdarrenr 27260855Sdarrenr 27392685Sdarrenr/* 27492685Sdarrenr * Return 1 if the packet is a good match against a proxy, else 0. 27592685Sdarrenr */ 276145522Sdarrenrint appr_ok(fin, tcp, nat) 277145522Sdarrenrfr_info_t *fin; 27853642Sguidotcphdr_t *tcp; 27953642Sguidoipnat_t *nat; 28053642Sguido{ 28153642Sguido aproxy_t *apr = nat->in_apr; 28253642Sguido u_short dport = nat->in_dport; 28353642Sguido 28492685Sdarrenr if ((apr == NULL) || (apr->apr_flags & APR_DELETE) || 285145522Sdarrenr (fin->fin_p != apr->apr_p)) 28653642Sguido return 0; 287145522Sdarrenr if ((tcp == NULL) && dport) 28853642Sguido return 0; 28953642Sguido return 1; 29053642Sguido} 29153642Sguido 29253642Sguido 293145522Sdarrenrint appr_ioctl(data, cmd, mode) 294145522Sdarrenrcaddr_t data; 295145522Sdarrenrioctlcmd_t cmd; 296145522Sdarrenrint mode; 297145522Sdarrenr{ 298145522Sdarrenr ap_ctl_t ctl; 299145522Sdarrenr caddr_t ptr; 300145522Sdarrenr int error; 301145522Sdarrenr 302145522Sdarrenr mode = mode; /* LINT */ 303145522Sdarrenr 304145522Sdarrenr switch (cmd) 305145522Sdarrenr { 306145522Sdarrenr case SIOCPROXY : 307145522Sdarrenr BCOPYIN(data, &ctl, sizeof(ctl)); 308145522Sdarrenr ptr = NULL; 309145522Sdarrenr 310145522Sdarrenr if (ctl.apc_dsize > 0) { 311145522Sdarrenr KMALLOCS(ptr, caddr_t, ctl.apc_dsize); 312145522Sdarrenr if (ptr == NULL) 313145522Sdarrenr error = ENOMEM; 314145522Sdarrenr else { 315145522Sdarrenr error = copyinptr(ctl.apc_data, ptr, 316145522Sdarrenr ctl.apc_dsize); 317145522Sdarrenr if (error == 0) 318145522Sdarrenr ctl.apc_data = ptr; 319145522Sdarrenr } 320145522Sdarrenr } else { 321145522Sdarrenr ctl.apc_data = NULL; 322145522Sdarrenr error = 0; 323145522Sdarrenr } 324145522Sdarrenr 325145522Sdarrenr if (error == 0) 326145522Sdarrenr error = appr_ctl(&ctl); 327145522Sdarrenr 328145522Sdarrenr if ((ctl.apc_dsize > 0) && (ptr != NULL) && 329145522Sdarrenr (ctl.apc_data == ptr)) { 330145522Sdarrenr KFREES(ptr, ctl.apc_dsize); 331145522Sdarrenr } 332145522Sdarrenr break; 333145522Sdarrenr 334145522Sdarrenr default : 335145522Sdarrenr error = EINVAL; 336145522Sdarrenr } 337145522Sdarrenr return error; 338145522Sdarrenr} 339145522Sdarrenr 340145522Sdarrenr 34153642Sguido/* 34292685Sdarrenr * If a proxy has a match function, call that to do extended packet 34392685Sdarrenr * matching. 34492685Sdarrenr */ 34592685Sdarrenrint appr_match(fin, nat) 34692685Sdarrenrfr_info_t *fin; 34792685Sdarrenrnat_t *nat; 34892685Sdarrenr{ 34992685Sdarrenr aproxy_t *apr; 35092685Sdarrenr ipnat_t *ipn; 351145522Sdarrenr int result; 35292685Sdarrenr 35392685Sdarrenr ipn = nat->nat_ptr; 354145522Sdarrenr if (ipf_proxy_debug > 8) 355145522Sdarrenr printf("appr_match(%lx,%lx) aps %lx ptr %lx\n", 356145522Sdarrenr (u_long)fin, (u_long)nat, (u_long)nat->nat_aps, 357145522Sdarrenr (u_long)ipn); 358145522Sdarrenr 359145522Sdarrenr if ((fin->fin_flx & (FI_SHORT|FI_BAD)) != 0) { 360145522Sdarrenr if (ipf_proxy_debug > 0) 361145522Sdarrenr printf("appr_match: flx 0x%x (BAD|SHORT)\n", 362145522Sdarrenr fin->fin_flx); 36392685Sdarrenr return -1; 364145522Sdarrenr } 365145522Sdarrenr 36692685Sdarrenr apr = ipn->in_apr; 367145522Sdarrenr if ((apr == NULL) || (apr->apr_flags & APR_DELETE)) { 368145522Sdarrenr if (ipf_proxy_debug > 0) 369145522Sdarrenr printf("appr_match:apr %lx apr_flags 0x%x\n", 370145522Sdarrenr (u_long)apr, apr ? apr->apr_flags : 0); 37192685Sdarrenr return -1; 372145522Sdarrenr } 373145522Sdarrenr 374145522Sdarrenr if (apr->apr_match != NULL) { 375145522Sdarrenr result = (*apr->apr_match)(fin, nat->nat_aps, nat); 376145522Sdarrenr if (result != 0) { 377145522Sdarrenr if (ipf_proxy_debug > 4) 378145522Sdarrenr printf("appr_match: result %d\n", result); 37992685Sdarrenr return -1; 380145522Sdarrenr } 381145522Sdarrenr } 38292685Sdarrenr return 0; 38392685Sdarrenr} 38492685Sdarrenr 38592685Sdarrenr 38692685Sdarrenr/* 38753642Sguido * Allocate a new application proxy structure and fill it in with the 38853642Sguido * relevant details. call the init function once complete, prior to 38953642Sguido * returning. 39053642Sguido */ 391145522Sdarrenrint appr_new(fin, nat) 39292685Sdarrenrfr_info_t *fin; 39353642Sguidonat_t *nat; 39453642Sguido{ 39553642Sguido register ap_session_t *aps; 39692685Sdarrenr aproxy_t *apr; 39753642Sguido 398145522Sdarrenr if (ipf_proxy_debug > 8) 399145522Sdarrenr printf("appr_new(%lx,%lx) \n", (u_long)fin, (u_long)nat); 400145522Sdarrenr 401145522Sdarrenr if ((nat->nat_ptr == NULL) || (nat->nat_aps != NULL)) { 402145522Sdarrenr if (ipf_proxy_debug > 0) 403145522Sdarrenr printf("appr_new: nat_ptr %lx nat_aps %lx\n", 404145522Sdarrenr (u_long)nat->nat_ptr, (u_long)nat->nat_aps); 40592685Sdarrenr return -1; 406145522Sdarrenr } 40792685Sdarrenr 40892685Sdarrenr apr = nat->nat_ptr->in_apr; 40992685Sdarrenr 410145522Sdarrenr if ((apr->apr_flags & APR_DELETE) || 411145522Sdarrenr (fin->fin_p != apr->apr_p)) { 412145522Sdarrenr if (ipf_proxy_debug > 2) 413145522Sdarrenr printf("appr_new: apr_flags 0x%x p %d/%d\n", 414145522Sdarrenr apr->apr_flags, fin->fin_p, apr->apr_p); 41592685Sdarrenr return -1; 416145522Sdarrenr } 41753642Sguido 41853642Sguido KMALLOC(aps, ap_session_t *); 419145522Sdarrenr if (!aps) { 420145522Sdarrenr if (ipf_proxy_debug > 0) 421145522Sdarrenr printf("appr_new: malloc failed (%lu)\n", 422145522Sdarrenr (u_long)sizeof(ap_session_t)); 42392685Sdarrenr return -1; 424145522Sdarrenr } 425145522Sdarrenr 42653642Sguido bzero((char *)aps, sizeof(*aps)); 427145522Sdarrenr aps->aps_p = fin->fin_p; 42853642Sguido aps->aps_data = NULL; 42953642Sguido aps->aps_apr = apr; 43053642Sguido aps->aps_psiz = 0; 43160855Sdarrenr if (apr->apr_new != NULL) 432145522Sdarrenr if ((*apr->apr_new)(fin, aps, nat) == -1) { 43392685Sdarrenr if ((aps->aps_data != NULL) && (aps->aps_psiz != 0)) { 43492685Sdarrenr KFREES(aps->aps_data, aps->aps_psiz); 43592685Sdarrenr } 43660855Sdarrenr KFREE(aps); 437145522Sdarrenr if (ipf_proxy_debug > 2) 438145522Sdarrenr printf("appr_new: new(%lx) failed\n", 439145522Sdarrenr (u_long)apr->apr_new); 44092685Sdarrenr return -1; 44160855Sdarrenr } 44260855Sdarrenr aps->aps_nat = nat; 44360855Sdarrenr aps->aps_next = ap_sess_list; 44453642Sguido ap_sess_list = aps; 44592685Sdarrenr nat->nat_aps = aps; 44692685Sdarrenr 44792685Sdarrenr return 0; 44853642Sguido} 44953642Sguido 45053642Sguido 45153642Sguido/* 452145522Sdarrenr * Check to see if a packet should be passed through an active proxy routine 453145522Sdarrenr * if one has been setup for it. We don't need to check the checksum here if 454145522Sdarrenr * IPFILTER_CKSUM is defined because if it is, a failed check causes FI_BAD 455145522Sdarrenr * to be set. 45653642Sguido */ 457145522Sdarrenrint appr_check(fin, nat) 45853642Sguidofr_info_t *fin; 45953642Sguidonat_t *nat; 46053642Sguido{ 46180482Sdarrenr#if SOLARIS && defined(_KERNEL) && (SOLARIS2 >= 6) 462145522Sdarrenr# if defined(ICK_VALID) 463145522Sdarrenr mb_t *m; 464145522Sdarrenr# endif 46580482Sdarrenr int dosum = 1; 46680482Sdarrenr#endif 46780482Sdarrenr tcphdr_t *tcp = NULL; 468145522Sdarrenr udphdr_t *udp = NULL; 46953642Sguido ap_session_t *aps; 47053642Sguido aproxy_t *apr; 471145522Sdarrenr ip_t *ip; 47260855Sdarrenr short rv; 47353642Sguido int err; 474145522Sdarrenr#if !defined(_KERNEL) || defined(MENTAT) || defined(__sgi) 475145522Sdarrenr u_32_t s1, s2, sd; 476145522Sdarrenr#endif 47753642Sguido 478145522Sdarrenr if (fin->fin_flx & FI_BAD) { 479145522Sdarrenr if (ipf_proxy_debug > 0) 480145522Sdarrenr printf("appr_check: flx 0x%x (BAD)\n", fin->fin_flx); 481145522Sdarrenr return -1; 482145522Sdarrenr } 483145522Sdarrenr 484145522Sdarrenr#ifndef IPFILTER_CKSUM 485145522Sdarrenr if ((fin->fin_out == 0) && (fr_checkl4sum(fin) == -1)) { 486145522Sdarrenr if (ipf_proxy_debug > 0) 487145522Sdarrenr printf("appr_check: l4 checksum failure %d\n", 488145522Sdarrenr fin->fin_p); 489145522Sdarrenr if (fin->fin_p == IPPROTO_TCP) 490145522Sdarrenr frstats[fin->fin_out].fr_tcpbad++; 491145522Sdarrenr return -1; 492145522Sdarrenr } 493145522Sdarrenr#endif 494145522Sdarrenr 49553642Sguido aps = nat->nat_aps; 496145522Sdarrenr if ((aps != NULL) && (aps->aps_p == fin->fin_p)) { 497145522Sdarrenr /* 498145522Sdarrenr * If there is data in this packet to be proxied then try and 499145522Sdarrenr * get it all into the one buffer, else drop it. 500145522Sdarrenr */ 501145522Sdarrenr#if defined(MENTAT) || defined(HAVE_M_PULLDOWN) 502145522Sdarrenr if ((fin->fin_dlen > 0) && !(fin->fin_flx & FI_COALESCE)) 503145522Sdarrenr if (fr_coalesce(fin) == -1) { 504145522Sdarrenr if (ipf_proxy_debug > 0) 505145522Sdarrenr printf("appr_check: fr_coalesce failed %x\n", fin->fin_flx); 506145522Sdarrenr return -1; 507145522Sdarrenr } 508145522Sdarrenr#endif 509145522Sdarrenr ip = fin->fin_ip; 510145522Sdarrenr 511145522Sdarrenr switch (fin->fin_p) 512145522Sdarrenr { 513145522Sdarrenr case IPPROTO_TCP : 51453642Sguido tcp = (tcphdr_t *)fin->fin_dp; 515145522Sdarrenr 516145522Sdarrenr#if SOLARIS && defined(_KERNEL) && (SOLARIS2 >= 6) && defined(ICK_VALID) 517145522Sdarrenr m = fin->fin_qfm; 518145522Sdarrenr if (dohwcksum && (m->b_ick_flag == ICK_VALID)) 51980482Sdarrenr dosum = 0; 52053642Sguido#endif 521102520Sdarrenr /* 522110916Sdarrenr * Don't bother the proxy with these...or in fact, 523110916Sdarrenr * should we free up proxy stuff when seen? 524102520Sdarrenr */ 525145522Sdarrenr if ((fin->fin_tcpf & TH_RST) != 0) 526145522Sdarrenr break; 527145522Sdarrenr /*FALLTHROUGH*/ 528145522Sdarrenr case IPPROTO_UDP : 529145522Sdarrenr udp = (udphdr_t *)fin->fin_dp; 530145522Sdarrenr break; 531145522Sdarrenr default : 532145522Sdarrenr break; 53353642Sguido } 53453642Sguido 53553642Sguido apr = aps->aps_apr; 53653642Sguido err = 0; 53753642Sguido if (fin->fin_out != 0) { 53853642Sguido if (apr->apr_outpkt != NULL) 539145522Sdarrenr err = (*apr->apr_outpkt)(fin, aps, nat); 54053642Sguido } else { 54153642Sguido if (apr->apr_inpkt != NULL) 542145522Sdarrenr err = (*apr->apr_inpkt)(fin, aps, nat); 54353642Sguido } 54453642Sguido 54560855Sdarrenr rv = APR_EXIT(err); 546145522Sdarrenr if (((ipf_proxy_debug > 0) && (rv != 0)) || 547145522Sdarrenr (ipf_proxy_debug > 8)) 548145522Sdarrenr printf("appr_check: out %d err %x rv %d\n", 549145522Sdarrenr fin->fin_out, err, rv); 550145522Sdarrenr if (rv == 1) 55192685Sdarrenr return -1; 552145522Sdarrenr 55392685Sdarrenr if (rv == 2) { 55492685Sdarrenr appr_free(apr); 55592685Sdarrenr nat->nat_aps = NULL; 55692685Sdarrenr return -1; 55792685Sdarrenr } 55860855Sdarrenr 559145522Sdarrenr /* 560145522Sdarrenr * If err != 0 then the data size of the packet has changed 561145522Sdarrenr * so we need to recalculate the header checksums for the 562145522Sdarrenr * packet. 563145522Sdarrenr */ 564145522Sdarrenr#if !defined(_KERNEL) || defined(MENTAT) || defined(__sgi) 565145522Sdarrenr if (err != 0) { 566145522Sdarrenr short adjlen = err & 0xffff; 567145522Sdarrenr 568145522Sdarrenr s1 = LONG_SUM(ip->ip_len - adjlen); 569145522Sdarrenr s2 = LONG_SUM(ip->ip_len); 570145522Sdarrenr CALC_SUMD(s1, s2, sd); 571145522Sdarrenr fix_outcksum(fin, &ip->ip_sum, sd); 572145522Sdarrenr } 573145522Sdarrenr#endif 574145522Sdarrenr 575145522Sdarrenr /* 576145522Sdarrenr * For TCP packets, we may need to adjust the sequence and 577145522Sdarrenr * acknowledgement numbers to reflect changes in size of the 578145522Sdarrenr * data stream. 579145522Sdarrenr * 580145522Sdarrenr * For both TCP and UDP, recalculate the layer 4 checksum, 581145522Sdarrenr * regardless, as we can't tell (here) if data has been 582145522Sdarrenr * changed or not. 583145522Sdarrenr */ 58453642Sguido if (tcp != NULL) { 58560855Sdarrenr err = appr_fixseqack(fin, ip, aps, APR_INC(err)); 58680482Sdarrenr#if SOLARIS && defined(_KERNEL) && (SOLARIS2 >= 6) 58780482Sdarrenr if (dosum) 588145522Sdarrenr tcp->th_sum = fr_cksum(fin->fin_qfm, ip, 589145522Sdarrenr IPPROTO_TCP, tcp); 59053642Sguido#else 591145522Sdarrenr tcp->th_sum = fr_cksum(fin->fin_m, ip, 592145522Sdarrenr IPPROTO_TCP, tcp); 59353642Sguido#endif 594145522Sdarrenr } else if ((udp != NULL) && (udp->uh_sum != 0)) { 595145522Sdarrenr#if SOLARIS && defined(_KERNEL) && (SOLARIS2 >= 6) 596145522Sdarrenr if (dosum) 597145522Sdarrenr udp->uh_sum = fr_cksum(fin->fin_qfm, ip, 598145522Sdarrenr IPPROTO_UDP, udp); 599145522Sdarrenr#else 600145522Sdarrenr udp->uh_sum = fr_cksum(fin->fin_m, ip, 601145522Sdarrenr IPPROTO_UDP, udp); 602145522Sdarrenr#endif 60353642Sguido } 604145522Sdarrenr aps->aps_bytes += fin->fin_plen; 60553642Sguido aps->aps_pkts++; 60660855Sdarrenr return 1; 60753642Sguido } 60860855Sdarrenr return 0; 60953642Sguido} 61053642Sguido 61153642Sguido 61292685Sdarrenr/* 61392685Sdarrenr * Search for an proxy by the protocol it is being used with and its name. 61492685Sdarrenr */ 61592685Sdarrenraproxy_t *appr_lookup(pr, name) 61653642Sguidou_int pr; 61753642Sguidochar *name; 61853642Sguido{ 61953642Sguido aproxy_t *ap; 62053642Sguido 621145522Sdarrenr if (ipf_proxy_debug > 8) 622145522Sdarrenr printf("appr_lookup(%d,%s)\n", pr, name); 623145522Sdarrenr 62453642Sguido for (ap = ap_proxies; ap->apr_p; ap++) 62553642Sguido if ((ap->apr_p == pr) && 62653642Sguido !strncmp(name, ap->apr_label, sizeof(ap->apr_label))) { 62753642Sguido ap->apr_ref++; 62853642Sguido return ap; 62953642Sguido } 63060855Sdarrenr 63160855Sdarrenr for (ap = ap_proxylist; ap; ap = ap->apr_next) 63260855Sdarrenr if ((ap->apr_p == pr) && 63360855Sdarrenr !strncmp(name, ap->apr_label, sizeof(ap->apr_label))) { 63460855Sdarrenr ap->apr_ref++; 63560855Sdarrenr return ap; 63660855Sdarrenr } 637145522Sdarrenr if (ipf_proxy_debug > 2) 638145522Sdarrenr printf("appr_lookup: failed for %d/%s\n", pr, name); 63953642Sguido return NULL; 64053642Sguido} 64153642Sguido 64253642Sguido 64353642Sguidovoid appr_free(ap) 64453642Sguidoaproxy_t *ap; 64553642Sguido{ 64653642Sguido ap->apr_ref--; 64753642Sguido} 64853642Sguido 64953642Sguido 65053642Sguidovoid aps_free(aps) 65153642Sguidoap_session_t *aps; 65253642Sguido{ 65353642Sguido ap_session_t *a, **ap; 65492685Sdarrenr aproxy_t *apr; 65553642Sguido 65653642Sguido if (!aps) 65753642Sguido return; 65853642Sguido 659145522Sdarrenr for (ap = &ap_sess_list; ((a = *ap) != NULL); ap = &a->aps_next) 66053642Sguido if (a == aps) { 66153642Sguido *ap = a->aps_next; 66253642Sguido break; 66353642Sguido } 66453642Sguido 66592685Sdarrenr apr = aps->aps_apr; 66692685Sdarrenr if ((apr != NULL) && (apr->apr_del != NULL)) 66792685Sdarrenr (*apr->apr_del)(aps); 668110916Sdarrenr 66960855Sdarrenr if ((aps->aps_data != NULL) && (aps->aps_psiz != 0)) 67060855Sdarrenr KFREES(aps->aps_data, aps->aps_psiz); 67160855Sdarrenr KFREE(aps); 67253642Sguido} 67353642Sguido 67453642Sguido 675102520Sdarrenr/* 676102520Sdarrenr * returns 2 if ack or seq number in TCP header is changed, returns 0 otherwise 677102520Sdarrenr */ 67853642Sguidostatic int appr_fixseqack(fin, ip, aps, inc) 67953642Sguidofr_info_t *fin; 68053642Sguidoip_t *ip; 68153642Sguidoap_session_t *aps; 68253642Sguidoint inc; 68353642Sguido{ 68453642Sguido int sel, ch = 0, out, nlen; 68553642Sguido u_32_t seq1, seq2; 68653642Sguido tcphdr_t *tcp; 68798004Sdarrenr short inc2; 68853642Sguido 68953642Sguido tcp = (tcphdr_t *)fin->fin_dp; 69053642Sguido out = fin->fin_out; 691102520Sdarrenr /* 692102520Sdarrenr * ip_len has already been adjusted by 'inc'. 693102520Sdarrenr */ 69453642Sguido nlen = ip->ip_len; 695145522Sdarrenr nlen -= (IP_HL(ip) << 2) + (TCP_OFF(tcp) << 2); 696102520Sdarrenr 69798004Sdarrenr inc2 = inc; 69898004Sdarrenr inc = (int)inc2; 69953642Sguido 70053642Sguido if (out != 0) { 70153642Sguido seq1 = (u_32_t)ntohl(tcp->th_seq); 70253642Sguido sel = aps->aps_sel[out]; 70353642Sguido 70453642Sguido /* switch to other set ? */ 70553642Sguido if ((aps->aps_seqmin[!sel] > aps->aps_seqmin[sel]) && 706102520Sdarrenr (seq1 > aps->aps_seqmin[!sel])) { 707145522Sdarrenr if (ipf_proxy_debug > 7) 708145522Sdarrenr printf("proxy out switch set seq %d -> %d %x > %x\n", 709145522Sdarrenr sel, !sel, seq1, 710145522Sdarrenr aps->aps_seqmin[!sel]); 71153642Sguido sel = aps->aps_sel[out] = !sel; 712110916Sdarrenr } 71353642Sguido 71453642Sguido if (aps->aps_seqoff[sel]) { 71553642Sguido seq2 = aps->aps_seqmin[sel] - aps->aps_seqoff[sel]; 71653642Sguido if (seq1 > seq2) { 71753642Sguido seq2 = aps->aps_seqoff[sel]; 71853642Sguido seq1 += seq2; 71953642Sguido tcp->th_seq = htonl(seq1); 72053642Sguido ch = 1; 72153642Sguido } 72253642Sguido } 72353642Sguido 72453642Sguido if (inc && (seq1 > aps->aps_seqmin[!sel])) { 725102520Sdarrenr aps->aps_seqmin[sel] = seq1 + nlen - 1; 726102520Sdarrenr aps->aps_seqoff[sel] = aps->aps_seqoff[sel] + inc; 727145522Sdarrenr if (ipf_proxy_debug > 7) 728145522Sdarrenr printf("proxy seq set %d at %x to %d + %d\n", 729145522Sdarrenr sel, aps->aps_seqmin[sel], 730145522Sdarrenr aps->aps_seqoff[sel], inc); 73153642Sguido } 73253642Sguido 73353642Sguido /***/ 73453642Sguido 73553642Sguido seq1 = ntohl(tcp->th_ack); 73653642Sguido sel = aps->aps_sel[1 - out]; 73753642Sguido 73853642Sguido /* switch to other set ? */ 73953642Sguido if ((aps->aps_ackmin[!sel] > aps->aps_ackmin[sel]) && 740102520Sdarrenr (seq1 > aps->aps_ackmin[!sel])) { 741145522Sdarrenr if (ipf_proxy_debug > 7) 742145522Sdarrenr printf("proxy out switch set ack %d -> %d %x > %x\n", 743145522Sdarrenr sel, !sel, seq1, 744145522Sdarrenr aps->aps_ackmin[!sel]); 74553642Sguido sel = aps->aps_sel[1 - out] = !sel; 746110916Sdarrenr } 74753642Sguido 74853642Sguido if (aps->aps_ackoff[sel] && (seq1 > aps->aps_ackmin[sel])) { 74953642Sguido seq2 = aps->aps_ackoff[sel]; 75053642Sguido tcp->th_ack = htonl(seq1 - seq2); 75153642Sguido ch = 1; 75253642Sguido } 75353642Sguido } else { 75453642Sguido seq1 = ntohl(tcp->th_seq); 75553642Sguido sel = aps->aps_sel[out]; 75653642Sguido 75753642Sguido /* switch to other set ? */ 75853642Sguido if ((aps->aps_ackmin[!sel] > aps->aps_ackmin[sel]) && 759102520Sdarrenr (seq1 > aps->aps_ackmin[!sel])) { 760145522Sdarrenr if (ipf_proxy_debug > 7) 761145522Sdarrenr printf("proxy in switch set ack %d -> %d %x > %x\n", 762145522Sdarrenr sel, !sel, seq1, aps->aps_ackmin[!sel]); 76353642Sguido sel = aps->aps_sel[out] = !sel; 764110916Sdarrenr } 76553642Sguido 76653642Sguido if (aps->aps_ackoff[sel]) { 767102520Sdarrenr seq2 = aps->aps_ackmin[sel] - aps->aps_ackoff[sel]; 76853642Sguido if (seq1 > seq2) { 76953642Sguido seq2 = aps->aps_ackoff[sel]; 77053642Sguido seq1 += seq2; 77153642Sguido tcp->th_seq = htonl(seq1); 77253642Sguido ch = 1; 77353642Sguido } 77453642Sguido } 77553642Sguido 77653642Sguido if (inc && (seq1 > aps->aps_ackmin[!sel])) { 77753642Sguido aps->aps_ackmin[!sel] = seq1 + nlen - 1; 77853642Sguido aps->aps_ackoff[!sel] = aps->aps_ackoff[sel] + inc; 779145522Sdarrenr 780145522Sdarrenr if (ipf_proxy_debug > 7) 781145522Sdarrenr printf("proxy ack set %d at %x to %d + %d\n", 782145522Sdarrenr !sel, aps->aps_seqmin[!sel], 783145522Sdarrenr aps->aps_seqoff[sel], inc); 78453642Sguido } 78553642Sguido 78653642Sguido /***/ 78753642Sguido 78853642Sguido seq1 = ntohl(tcp->th_ack); 78953642Sguido sel = aps->aps_sel[1 - out]; 79053642Sguido 79153642Sguido /* switch to other set ? */ 79253642Sguido if ((aps->aps_seqmin[!sel] > aps->aps_seqmin[sel]) && 793102520Sdarrenr (seq1 > aps->aps_seqmin[!sel])) { 794145522Sdarrenr if (ipf_proxy_debug > 7) 795145522Sdarrenr printf("proxy in switch set seq %d -> %d %x > %x\n", 796145522Sdarrenr sel, !sel, seq1, aps->aps_seqmin[!sel]); 79753642Sguido sel = aps->aps_sel[1 - out] = !sel; 798110916Sdarrenr } 79953642Sguido 800102520Sdarrenr if (aps->aps_seqoff[sel] != 0) { 801145522Sdarrenr if (ipf_proxy_debug > 7) 802145522Sdarrenr printf("sel %d seqoff %d seq1 %x seqmin %x\n", 803145522Sdarrenr sel, aps->aps_seqoff[sel], seq1, 804145522Sdarrenr aps->aps_seqmin[sel]); 805102520Sdarrenr if (seq1 > aps->aps_seqmin[sel]) { 806102520Sdarrenr seq2 = aps->aps_seqoff[sel]; 807102520Sdarrenr tcp->th_ack = htonl(seq1 - seq2); 808102520Sdarrenr ch = 1; 809102520Sdarrenr } 81053642Sguido } 81153642Sguido } 812145522Sdarrenr 813145522Sdarrenr if (ipf_proxy_debug > 8) 814145522Sdarrenr printf("appr_fixseqack: seq %x ack %x\n", 815145522Sdarrenr ntohl(tcp->th_seq), ntohl(tcp->th_ack)); 81653642Sguido return ch ? 2 : 0; 81753642Sguido} 81853642Sguido 81953642Sguido 82092685Sdarrenr/* 82192685Sdarrenr * Initialise hook for kernel application proxies. 82292685Sdarrenr * Call the initialise routine for all the compiled in kernel proxies. 82392685Sdarrenr */ 82453642Sguidoint appr_init() 82553642Sguido{ 82653642Sguido aproxy_t *ap; 82753642Sguido int err = 0; 82853642Sguido 82953642Sguido for (ap = ap_proxies; ap->apr_p; ap++) { 830145522Sdarrenr if (ap->apr_init != NULL) { 831145522Sdarrenr err = (*ap->apr_init)(); 832145522Sdarrenr if (err != 0) 833145522Sdarrenr break; 834145522Sdarrenr } 83553642Sguido } 83653642Sguido return err; 83753642Sguido} 83860855Sdarrenr 83960855Sdarrenr 84092685Sdarrenr/* 84192685Sdarrenr * Unload hook for kernel application proxies. 84292685Sdarrenr * Call the finialise routine for all the compiled in kernel proxies. 84392685Sdarrenr */ 84460855Sdarrenrvoid appr_unload() 84560855Sdarrenr{ 84660855Sdarrenr aproxy_t *ap; 84760855Sdarrenr 84860855Sdarrenr for (ap = ap_proxies; ap->apr_p; ap++) 849145522Sdarrenr if (ap->apr_fini != NULL) 85060855Sdarrenr (*ap->apr_fini)(); 85160855Sdarrenr for (ap = ap_proxylist; ap; ap = ap->apr_next) 852145522Sdarrenr if (ap->apr_fini != NULL) 85360855Sdarrenr (*ap->apr_fini)(); 85460855Sdarrenr} 855