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