ip_proxy.c revision 80482
1/* 2 * Copyright (C) 1997-2001 by Darren Reed. 3 * 4 * See the IPFILTER.LICENCE file for details on licencing. 5 */ 6 7#if defined(__FreeBSD__) && defined(KERNEL) && !defined(_KERNEL) 8# define _KERNEL 9#endif 10 11#include <sys/errno.h> 12#include <sys/types.h> 13#include <sys/param.h> 14#include <sys/time.h> 15#include <sys/file.h> 16#if !defined(__FreeBSD_version) 17# include <sys/ioctl.h> 18#endif 19#include <sys/fcntl.h> 20#include <sys/uio.h> 21#if !defined(_KERNEL) && !defined(KERNEL) 22# include <stdio.h> 23# include <string.h> 24# include <stdlib.h> 25#endif 26#ifndef linux 27# include <sys/protosw.h> 28#endif 29#include <sys/socket.h> 30#if defined(_KERNEL) 31# if !defined(linux) 32# include <sys/systm.h> 33# else 34# include <linux/string.h> 35# endif 36#endif 37#if !defined(__SVR4) && !defined(__svr4__) 38# ifndef linux 39# include <sys/mbuf.h> 40# endif 41#else 42# include <sys/byteorder.h> 43# ifdef _KERNEL 44# include <sys/dditypes.h> 45# endif 46# include <sys/stream.h> 47# include <sys/kmem.h> 48#endif 49#if __FreeBSD__ > 2 50# include <sys/queue.h> 51#endif 52#include <net/if.h> 53#ifdef sun 54# include <net/af.h> 55#endif 56#include <net/route.h> 57#include <netinet/in.h> 58#include <netinet/in_systm.h> 59#include <netinet/ip.h> 60#ifndef linux 61# include <netinet/ip_var.h> 62#endif 63#include <netinet/tcp.h> 64#include <netinet/udp.h> 65#include <netinet/ip_icmp.h> 66#include "netinet/ip_compat.h" 67#include <netinet/tcpip.h> 68#include "netinet/ip_fil.h" 69#include "netinet/ip_proxy.h" 70#include "netinet/ip_nat.h" 71#include "netinet/ip_state.h" 72#if (__FreeBSD_version >= 300000) 73# include <sys/malloc.h> 74#endif 75 76#if !defined(lint) 77/* static const char rcsid[] = "@(#)$Id: ip_proxy.c,v 2.9.2.6 2001/07/15 22:06:15 darrenr Exp $"; */ 78static const char rcsid[] = "@(#)$FreeBSD: head/sys/contrib/ipfilter/netinet/ip_proxy.c 80482 2001-07-28 11:58:26Z darrenr $"; 79#endif 80 81 82#ifndef MIN 83#define MIN(a,b) (((a)<(b))?(a):(b)) 84#endif 85 86static ap_session_t *appr_new_session __P((aproxy_t *, ip_t *, 87 fr_info_t *, nat_t *)); 88static int appr_fixseqack __P((fr_info_t *, ip_t *, ap_session_t *, int )); 89 90 91#define AP_SESS_SIZE 53 92 93#if defined(_KERNEL) && !defined(linux) 94#include "netinet/ip_ftp_pxy.c" 95#include "netinet/ip_rcmd_pxy.c" 96#include "netinet/ip_raudio_pxy.c" 97#endif 98 99ap_session_t *ap_sess_tab[AP_SESS_SIZE]; 100ap_session_t *ap_sess_list = NULL; 101aproxy_t *ap_proxylist = NULL; 102aproxy_t ap_proxies[] = { 103#ifdef IPF_FTP_PROXY 104 { NULL, "ftp", (char)IPPROTO_TCP, 0, 0, ippr_ftp_init, NULL, 105 ippr_ftp_new, ippr_ftp_in, ippr_ftp_out }, 106#endif 107#ifdef IPF_RCMD_PROXY 108 { NULL, "rcmd", (char)IPPROTO_TCP, 0, 0, ippr_rcmd_init, NULL, 109 ippr_rcmd_new, NULL, ippr_rcmd_out }, 110#endif 111#ifdef IPF_RAUDIO_PROXY 112 { NULL, "raudio", (char)IPPROTO_TCP, 0, 0, ippr_raudio_init, NULL, 113 ippr_raudio_new, ippr_raudio_in, ippr_raudio_out }, 114#endif 115 { NULL, "", '\0', 0, 0, NULL, NULL } 116}; 117 118 119int appr_add(ap) 120aproxy_t *ap; 121{ 122 aproxy_t *a; 123 124 for (a = ap_proxies; a->apr_p; a++) 125 if ((a->apr_p == ap->apr_p) && 126 !strncmp(a->apr_label, ap->apr_label, 127 sizeof(ap->apr_label))) 128 return -1; 129 130 for (a = ap_proxylist; a->apr_p; a = a->apr_next) 131 if ((a->apr_p == ap->apr_p) && 132 !strncmp(a->apr_label, ap->apr_label, 133 sizeof(ap->apr_label))) 134 return -1; 135 ap->apr_next = ap_proxylist; 136 ap_proxylist = ap; 137 return (*ap->apr_init)(); 138} 139 140 141int appr_del(ap) 142aproxy_t *ap; 143{ 144 aproxy_t *a, **app; 145 146 for (app = &ap_proxylist; (a = *app); app = &a->apr_next) 147 if (a == ap) { 148 if (ap->apr_ref != 0) 149 return 1; 150 *app = a->apr_next; 151 return 0; 152 } 153 return -1; 154} 155 156 157int appr_ok(ip, tcp, nat) 158ip_t *ip; 159tcphdr_t *tcp; 160ipnat_t *nat; 161{ 162 aproxy_t *apr = nat->in_apr; 163 u_short dport = nat->in_dport; 164 165 if (!apr || (apr->apr_flags & APR_DELETE) || 166 (ip->ip_p != apr->apr_p)) 167 return 0; 168 if ((tcp && (tcp->th_dport != dport)) || (!tcp && dport)) 169 return 0; 170 return 1; 171} 172 173 174/* 175 * Allocate a new application proxy structure and fill it in with the 176 * relevant details. call the init function once complete, prior to 177 * returning. 178 */ 179static ap_session_t *appr_new_session(apr, ip, fin, nat) 180aproxy_t *apr; 181ip_t *ip; 182fr_info_t *fin; 183nat_t *nat; 184{ 185 register ap_session_t *aps; 186 187 if (!apr || (apr->apr_flags & APR_DELETE) || (ip->ip_p != apr->apr_p)) 188 return NULL; 189 190 KMALLOC(aps, ap_session_t *); 191 if (!aps) 192 return NULL; 193 bzero((char *)aps, sizeof(*aps)); 194 aps->aps_p = ip->ip_p; 195 aps->aps_data = NULL; 196 aps->aps_apr = apr; 197 aps->aps_psiz = 0; 198 if (apr->apr_new != NULL) 199 if ((*apr->apr_new)(fin, ip, aps, nat) == -1) { 200 KFREE(aps); 201 return NULL; 202 } 203 aps->aps_nat = nat; 204 aps->aps_next = ap_sess_list; 205 ap_sess_list = aps; 206 return aps; 207} 208 209 210/* 211 * check to see if a packet should be passed through an active proxy routine 212 * if one has been setup for it. 213 */ 214int appr_check(ip, fin, nat) 215ip_t *ip; 216fr_info_t *fin; 217nat_t *nat; 218{ 219#if SOLARIS && defined(_KERNEL) && (SOLARIS2 >= 6) 220 mb_t *m = fin->fin_qfm; 221 int dosum = 1; 222#endif 223 tcphdr_t *tcp = NULL; 224 ap_session_t *aps; 225 aproxy_t *apr; 226 u_32_t sum; 227 short rv; 228 int err; 229 230 if (nat->nat_aps == NULL) 231 nat->nat_aps = appr_new_session(nat->nat_ptr->in_apr, ip, 232 fin, nat); 233 aps = nat->nat_aps; 234 if ((aps != NULL) && (aps->aps_p == ip->ip_p)) { 235 if (ip->ip_p == IPPROTO_TCP) { 236 tcp = (tcphdr_t *)fin->fin_dp; 237 /* 238 * verify that the checksum is correct. If not, then 239 * don't do anything with this packet. 240 */ 241#if SOLARIS && defined(_KERNEL) && (SOLARIS2 >= 6) 242 if (dohwcksum && (m->b_ick_flag == ICK_VALID)) { 243 sum = tcp->th_sum; 244 dosum = 0; 245 } 246 if (dosum) 247 sum = fr_tcpsum(fin->fin_qfm, ip, tcp); 248#else 249 sum = fr_tcpsum(*(mb_t **)fin->fin_mp, ip, tcp); 250#endif 251 if (sum != tcp->th_sum) { 252 frstats[fin->fin_out].fr_tcpbad++; 253 return -1; 254 } 255 } 256 257 apr = aps->aps_apr; 258 err = 0; 259 if (fin->fin_out != 0) { 260 if (apr->apr_outpkt != NULL) 261 err = (*apr->apr_outpkt)(fin, ip, aps, nat); 262 } else { 263 if (apr->apr_inpkt != NULL) 264 err = (*apr->apr_inpkt)(fin, ip, aps, nat); 265 } 266 267 rv = APR_EXIT(err); 268 if (rv == -1) 269 return rv; 270 271 if (tcp != NULL) { 272 err = appr_fixseqack(fin, ip, aps, APR_INC(err)); 273#if SOLARIS && defined(_KERNEL) && (SOLARIS2 >= 6) 274 if (dosum) 275 tcp->th_sum = fr_tcpsum(fin->fin_qfm, ip, tcp); 276#else 277 tcp->th_sum = fr_tcpsum(*(mb_t **)fin->fin_mp, ip, tcp); 278#endif 279 } 280 aps->aps_bytes += ip->ip_len; 281 aps->aps_pkts++; 282 return 1; 283 } 284 return 0; 285} 286 287 288aproxy_t *appr_match(pr, name) 289u_int pr; 290char *name; 291{ 292 aproxy_t *ap; 293 294 for (ap = ap_proxies; ap->apr_p; ap++) 295 if ((ap->apr_p == pr) && 296 !strncmp(name, ap->apr_label, sizeof(ap->apr_label))) { 297 ap->apr_ref++; 298 return ap; 299 } 300 301 for (ap = ap_proxylist; ap; ap = ap->apr_next) 302 if ((ap->apr_p == pr) && 303 !strncmp(name, ap->apr_label, sizeof(ap->apr_label))) { 304 ap->apr_ref++; 305 return ap; 306 } 307 return NULL; 308} 309 310 311void appr_free(ap) 312aproxy_t *ap; 313{ 314 ap->apr_ref--; 315} 316 317 318void aps_free(aps) 319ap_session_t *aps; 320{ 321 ap_session_t *a, **ap; 322 323 if (!aps) 324 return; 325 326 for (ap = &ap_sess_list; (a = *ap); ap = &a->aps_next) 327 if (a == aps) { 328 *ap = a->aps_next; 329 break; 330 } 331 332 if ((aps->aps_data != NULL) && (aps->aps_psiz != 0)) 333 KFREES(aps->aps_data, aps->aps_psiz); 334 KFREE(aps); 335} 336 337 338static int appr_fixseqack(fin, ip, aps, inc) 339fr_info_t *fin; 340ip_t *ip; 341ap_session_t *aps; 342int inc; 343{ 344 int sel, ch = 0, out, nlen; 345 u_32_t seq1, seq2; 346 tcphdr_t *tcp; 347 348 tcp = (tcphdr_t *)fin->fin_dp; 349 out = fin->fin_out; 350 nlen = ip->ip_len; 351 nlen -= (ip->ip_hl << 2) + (tcp->th_off << 2); 352 353 if (out != 0) { 354 seq1 = (u_32_t)ntohl(tcp->th_seq); 355 sel = aps->aps_sel[out]; 356 357 /* switch to other set ? */ 358 if ((aps->aps_seqmin[!sel] > aps->aps_seqmin[sel]) && 359 (seq1 > aps->aps_seqmin[!sel])) 360 sel = aps->aps_sel[out] = !sel; 361 362 if (aps->aps_seqoff[sel]) { 363 seq2 = aps->aps_seqmin[sel] - aps->aps_seqoff[sel]; 364 if (seq1 > seq2) { 365 seq2 = aps->aps_seqoff[sel]; 366 seq1 += seq2; 367 tcp->th_seq = htonl(seq1); 368 ch = 1; 369 } 370 } 371 372 if (inc && (seq1 > aps->aps_seqmin[!sel])) { 373 aps->aps_seqmin[!sel] = seq1 + nlen - 1; 374 aps->aps_seqoff[!sel] = aps->aps_seqoff[sel] + inc; 375 } 376 377 /***/ 378 379 seq1 = ntohl(tcp->th_ack); 380 sel = aps->aps_sel[1 - out]; 381 382 /* switch to other set ? */ 383 if ((aps->aps_ackmin[!sel] > aps->aps_ackmin[sel]) && 384 (seq1 > aps->aps_ackmin[!sel])) 385 sel = aps->aps_sel[1 - out] = !sel; 386 387 if (aps->aps_ackoff[sel] && (seq1 > aps->aps_ackmin[sel])) { 388 seq2 = aps->aps_ackoff[sel]; 389 tcp->th_ack = htonl(seq1 - seq2); 390 ch = 1; 391 } 392 } else { 393 seq1 = ntohl(tcp->th_seq); 394 sel = aps->aps_sel[out]; 395 396 /* switch to other set ? */ 397 if ((aps->aps_ackmin[!sel] > aps->aps_ackmin[sel]) && 398 (seq1 > aps->aps_ackmin[!sel])) 399 sel = aps->aps_sel[out] = !sel; 400 401 if (aps->aps_ackoff[sel]) { 402 seq2 = aps->aps_ackmin[sel] - 403 aps->aps_ackoff[sel]; 404 if (seq1 > seq2) { 405 seq2 = aps->aps_ackoff[sel]; 406 seq1 += seq2; 407 tcp->th_seq = htonl(seq1); 408 ch = 1; 409 } 410 } 411 412 if (inc && (seq1 > aps->aps_ackmin[!sel])) { 413 aps->aps_ackmin[!sel] = seq1 + nlen - 1; 414 aps->aps_ackoff[!sel] = aps->aps_ackoff[sel] + inc; 415 } 416 417 /***/ 418 419 seq1 = ntohl(tcp->th_ack); 420 sel = aps->aps_sel[1 - out]; 421 422 /* switch to other set ? */ 423 if ((aps->aps_seqmin[!sel] > aps->aps_seqmin[sel]) && 424 (seq1 > aps->aps_seqmin[!sel])) 425 sel = aps->aps_sel[1 - out] = !sel; 426 427 if (aps->aps_seqoff[sel] && (seq1 > aps->aps_seqmin[sel])) { 428 seq2 = aps->aps_seqoff[sel]; 429 tcp->th_ack = htonl(seq1 - seq2); 430 ch = 1; 431 } 432 } 433 return ch ? 2 : 0; 434} 435 436 437int appr_init() 438{ 439 aproxy_t *ap; 440 int err = 0; 441 442 for (ap = ap_proxies; ap->apr_p; ap++) { 443 err = (*ap->apr_init)(); 444 if (err != 0) 445 break; 446 } 447 return err; 448} 449 450 451void appr_unload() 452{ 453 aproxy_t *ap; 454 455 for (ap = ap_proxies; ap->apr_p; ap++) 456 if (ap->apr_fini) 457 (*ap->apr_fini)(); 458 for (ap = ap_proxylist; ap; ap = ap->apr_next) 459 if (ap->apr_fini) 460 (*ap->apr_fini)(); 461} 462