From acdb2ce24a62f8b955af761b992ae020cc2303ef Mon Sep 17 00:00:00 2001 From: Darren Reed Date: Sun, 25 May 1997 15:49:17 +0000 Subject: [PATCH] Import version 3.2alpha7 (they're currently in src/contrib/ipfilter/ipfilter/ by mistake, if someone from core would like to delete that directory with three files as I'm not meant to do that :) --- contrib/ipfilter/ip_ftp_pxy.c | 204 +++++++++++++++++++++++++ contrib/ipfilter/ip_proxy.c | 271 ++++++++++++++++++++++++++++++++++ contrib/ipfilter/ip_proxy.h | 89 +++++++++++ 3 files changed, 564 insertions(+) create mode 100644 contrib/ipfilter/ip_ftp_pxy.c create mode 100644 contrib/ipfilter/ip_proxy.c create mode 100644 contrib/ipfilter/ip_proxy.h diff --git a/contrib/ipfilter/ip_ftp_pxy.c b/contrib/ipfilter/ip_ftp_pxy.c new file mode 100644 index 00000000000..48196e97fd0 --- /dev/null +++ b/contrib/ipfilter/ip_ftp_pxy.c @@ -0,0 +1,204 @@ +/* + * Simple FTP transparent proxy for in-kernel. + */ + +#define isdigit(x) ((x) >= '0' && (x) <= '9') + +#define IPF_FTP_PROXY + +#define IPF_MINPORTLEN 18 +#define IPF_MAXPORTLEN 30 + + +int ippr_ftp_init(fin, ip, tcp, aps, nat) +fr_info_t *fin; +ip_t *ip; +tcphdr_t *tcp; +ap_session_t *aps; +nat_t *nat; +{ + aps->aps_sport = tcp->th_sport; + aps->aps_dport = tcp->th_dport; + return 0; +} + + +int ippr_ftp_in(fin, ip, tcp, aps, nat) +fr_info_t *fin; +ip_t *ip; +tcphdr_t *tcp; +ap_session_t *aps; +nat_t *nat; +{ + int ch = 0; + u_long sum1, sum2; + + if (tcp->th_dport != aps->aps_dport) { + sum2 = (u_long)ntohl(tcp->th_ack); + if (aps->aps_seqoff && (sum2 > aps->aps_after)) { + sum1 = (u_long)aps->aps_seqoff; + tcp->th_ack = htonl(sum2 - sum1); + return 2; + } + } + return 0; +} + + +u_short ipf_ftp_atoi(ptr) +char **ptr; +{ + register char *s = *ptr, c; + register u_char i = 0, j = 0; + + while ((c = *s++) && isdigit(c)) { + i *= 10; + i += c - '0'; + } + if (c != ',') { + *ptr = NULL; + return 0; + } + while ((c = *s++) && isdigit(c)) { + j *= 10; + j += c - '0'; + } + *ptr = s; + return (i << 8) | j; +} + + +int ippr_ftp_out(fin, ip, tcp, aps, nat) +fr_info_t *fin; +ip_t *ip; +tcphdr_t *tcp; +ap_session_t *aps; +nat_t *nat; +{ + register u_long sum1, sum2, sumd; + char newbuf[IPF_MAXPORTLEN+1]; + char portbuf[IPF_MAXPORTLEN+1], *s, c; + int ch = 0, off = (ip->ip_hl << 2) + (tcp->th_off << 2), len; + u_int a1, a2, a3, a4; + u_short a5, a6; + int olen, dlen, nlen, inc = 0, blen; + tcphdr_t tcph, *tcp2 = &tcph; + void *savep; + nat_t *ipn; + struct in_addr swip; +#if SOLARIS + mblk_t *m1, *m = *(mblk_t **)fin->fin_mp; + + dlen = m->b_wptr - m->b_rptr - off; + blen = m->b_datap->db_lim - m->b_datap->db_base; + bzero(portbuf, sizeof(portbuf)); + copyout_mblk(m, off, portbuf, MIN(sizeof(portbuf), dlen)); +#else + struct mbuf *m1, *m = *(struct mbuf **)fin->fin_mp; + + dlen = m->m_len - off; +# if BSD >= 199306 + blen = (MLEN - m->m_len) - (m->m_data - m->m_dat); +# else + blen = (MLEN - m->m_len) - m->m_off; +# endif + if (blen < 0) + panic("blen < 0 - size of mblk/mbuf wrong"); + bzero(portbuf, sizeof(portbuf)); + m_copydata(m, off, MIN(sizeof(portbuf), dlen), portbuf); +#endif + portbuf[IPF_MAXPORTLEN] = '\0'; + len = MIN(32, dlen); + + if ((len < IPF_MINPORTLEN) || strncmp(portbuf, "PORT ", 5)) + goto adjust_seqack; + + /* + * Skip the PORT command + space + */ + s = portbuf + 5; + /* + * Pick out the address components, two at a time. + */ + (void) ipf_ftp_atoi(&s); + if (!s) + goto adjust_seqack; + (void) ipf_ftp_atoi(&s); + if (!s) + goto adjust_seqack; + a5 = ipf_ftp_atoi(&s); + if (!s) + goto adjust_seqack; + /* + * check for CR-LF at the end. + */ + if (*s != '\n' || *(s - 1) != '\r') + goto adjust_seqack; + a6 = a5 & 0xff; + a5 >>= 8; + /* + * Calculate new address parts for PORT command + */ + a1 = ntohl(ip->ip_src.s_addr); + a2 = (a1 >> 16) & 0xff; + a3 = (a1 >> 8) & 0xff; + a4 = a1 & 0xff; + a1 >>= 24; + olen = s - portbuf + 1; + (void) sprintf(newbuf, "PORT %d,%d,%d,%d,%d,%d\r\n", + a1, a2, a3, a4, a5, a6); + nlen = strlen(newbuf); + inc = nlen - olen; + if (tcp->th_seq > aps->aps_after) { + aps->aps_after = ntohl(tcp->th_seq) + dlen; + aps->aps_seqoff += inc; + } +#if SOLARIS + if (inc && dlen) + if ((inc < 0) || (blen >= dlen)) { + bcopy(m->b_rptr + off, + m->b_rptr + off + aps->aps_seqoff, dlen); + } + for (m1 = m; m1->b_cont; m1 = m1->b_cont) + ; + m1->b_wptr += inc; + copyin_mblk(m, off, newbuf, strlen(newbuf)); +#else + if (inc && dlen) + if ((inc < 0) || (blen >= dlen)) { + bcopy((char *)ip + off, + (char *)ip + off + aps->aps_seqoff, dlen); + } + m->m_len += inc; + m_copyback(m, off, nlen, newbuf); +#endif + ip->ip_len += inc; + ch = 1; + + /* + * Add skeleton NAT entry for connection which will come back the + * other way. + */ + savep = fin->fin_dp; + fin->fin_dp = (char *)tcp2; + tcp2->th_sport = htons(a5 << 8 | a6); + tcp2->th_dport = htons(20); + swip = ip->ip_src; + ip->ip_src = nat->nat_inip; + if ((ipn = nat_new(nat->nat_ptr, ip, fin, IPN_TCP, NAT_OUTBOUND))) + ipn->nat_age = fr_defnatage; + ip->ip_src = swip; + fin->fin_dp = (char *)savep; + +adjust_seqack: + if (tcp->th_dport == aps->aps_dport) { + sum2 = (u_long)ntohl(tcp->th_seq); + if (aps->aps_seqoff && (sum2 > aps->aps_after)) { + sum1 = (u_long)aps->aps_seqoff; + tcp->th_seq = htonl(sum2 + sum1); + ch = 1; + } + } + + return ch ? 2 : 0; +} diff --git a/contrib/ipfilter/ip_proxy.c b/contrib/ipfilter/ip_proxy.c new file mode 100644 index 00000000000..16e5fbe2cf4 --- /dev/null +++ b/contrib/ipfilter/ip_proxy.c @@ -0,0 +1,271 @@ +/* + * (C)opyright 1997 by Darren Reed. + * + * Redistribution and use in source and binary forms are permitted + * provided that this notice is preserved and due credit is given + * to the original author and the contributors. + */ +#if !defined(lint) && defined(LIBC_SCCS) +static char rcsid[] = "$Id: ip_proxy.c,v 2.0.2.3 1997/05/24 07:36:22 darrenr Exp $"; +#endif + +#if defined(__FreeBSD__) && defined(KERNEL) && !defined(_KERNEL) +# define _KERNEL +#endif + +#if !defined(_KERNEL) && !defined(KERNEL) +# include +# include +# include +#endif +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef _KERNEL +# include +#endif +#if !defined(__SVR4) && !defined(__svr4__) +# include +#else +# include +# include +# include +# include +#endif +#if __FreeBSD__ > 2 +# include +#endif +#include +#ifdef sun +# include +#endif +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "netinet/ip_compat.h" +#include "netinet/ip_fil.h" +#include "netinet/ip_proxy.h" +#include "netinet/ip_nat.h" +#include "netinet/ip_state.h" + +#ifndef MIN +#define MIN(a,b) (((a)<(b))?(a):(b)) +#endif + +static ap_session_t *ap_find __P((ip_t *, tcphdr_t *)); +static ap_session_t *ap_new_session __P((aproxy_t *, ip_t *, tcphdr_t *, + fr_info_t *, nat_t *)); + +#define AP_SESS_SIZE 53 + +#ifdef _KERNEL +#include "netinet/ip_ftp_pxy.c" +#endif + +ap_session_t *ap_sess_tab[AP_SESS_SIZE]; +aproxy_t ap_proxies[] = { +#ifdef IPF_FTP_PROXY + { "ftp", (char)IPPROTO_TCP, 0, 0, ippr_ftp_init, ippr_ftp_in, ippr_ftp_out }, +#endif + { "", '\0', 0, 0, NULL, NULL } +}; + + +int ap_ok(ip, tcp, nat) +ip_t *ip; +tcphdr_t *tcp; +ipnat_t *nat; +{ + aproxy_t *apr = nat->in_apr; + u_short dport = nat->in_dport; + + if (!apr || (apr && (apr->apr_flags & APR_DELETE)) || + (ip->ip_p != apr->apr_p)) + return 0; + if ((tcp && (tcp->th_dport != dport)) || (!tcp && dport)) + return 0; + return 1; +} + + +static ap_session_t *ap_find(ip, tcp) +ip_t *ip; +tcphdr_t *tcp; +{ + struct in_addr src = ip->ip_src, dst = ip->ip_dst; + register u_long hv; + register u_short sp, dp; + register ap_session_t *aps; + register u_char p = ip->ip_p; + + hv = ip->ip_src.s_addr ^ ip->ip_dst.s_addr; + hv *= 651733; + if (tcp) { + sp = tcp->th_sport; + dp = tcp->th_dport; + hv ^= (sp + dp); + hv *= 5; + } + hv %= AP_SESS_SIZE; + + for (aps = ap_sess_tab[hv]; aps; aps = aps->aps_next) + if ((aps->aps_p == p) && + IPPAIR(aps->aps_src, aps->aps_dst, src, dst)) { + if (tcp) { + if (PAIRS(aps->aps_sport, aps->aps_dport, + sp, dp)) + break; + } else + break; + } + return aps; +} + +static ap_session_t *ap_new_session(apr, ip, tcp, fin, nat) +aproxy_t *apr; +ip_t *ip; +tcphdr_t *tcp; +fr_info_t *fin; +nat_t *nat; +{ + register ap_session_t *aps; + u_short dport; + u_long hv; + + if (!apr || (apr && (apr->apr_flags & APR_DELETE)) || + (ip->ip_p != apr->apr_p)) + return NULL; + dport = nat->nat_ptr->in_dport; + if ((tcp && (tcp->th_dport != dport)) || (!tcp && dport)) + return NULL; + + hv = ip->ip_src.s_addr ^ ip->ip_dst.s_addr; + hv *= 651733; + if (tcp) { + hv ^= (tcp->th_sport + tcp->th_dport); + hv *= 5; + } + hv %= AP_SESS_SIZE; + + KMALLOC(aps, ap_session_t *, sizeof(*aps)); + if (!aps) + return NULL; + bzero((char *)aps, sizeof(aps)); + apr->apr_ref++; + aps->aps_apr = apr; + aps->aps_src = ip->ip_src; + aps->aps_dst = ip->ip_dst; + aps->aps_p = ip->ip_p; + aps->aps_tout = 1200; /* XXX */ + if (tcp) { + if (ip->ip_p == IPPROTO_TCP) { + aps->aps_seqoff = 0; + aps->aps_ackoff = 0; + aps->aps_state[0] = 0; + aps->aps_state[1] = 0; + } + aps->aps_sport = tcp->th_sport; + aps->aps_dport = tcp->th_dport; + } + aps->aps_data = NULL; + aps->aps_psiz = 0; + aps->aps_next = ap_sess_tab[hv]; + ap_sess_tab[hv] = aps; + (void) (*apr->apr_init)(fin, ip, tcp, aps, nat); + return aps; +} + + +int ap_check(ip, tcp, fin, nat) +ip_t *ip; +tcphdr_t *tcp; +fr_info_t *fin; +nat_t *nat; +{ + ap_session_t *aps; + aproxy_t *apr; + int err; + + if (!(fin->fin_fi.fi_fl & FI_TCPUDP)) + tcp = NULL; + + if ((aps = ap_find(ip, tcp)) || + (aps = ap_new_session(nat->nat_ptr->in_apr, ip, tcp, fin, nat))) { + if (ip->ip_p == IPPROTO_TCP) + fr_tcp_age(&aps->aps_tout, aps->aps_state, ip, fin, + tcp->th_sport == aps->aps_sport); + apr = aps->aps_apr; + err = 0; + if (fin->fin_out) { + if (apr->apr_outpkt) + err = (*apr->apr_outpkt)(fin, ip, tcp, + aps, nat); + } else { + if (apr->apr_inpkt) + err = (*apr->apr_inpkt)(fin, ip, tcp, + aps, nat); + } + if (err == 2) { + tcp->th_sum = fr_tcpsum(fin->fin_mp, ip, tcp); + err = 0; + } + return err; + } + return -1; +} + + +aproxy_t *ap_match(pr, name) +char pr; +char *name; +{ + aproxy_t *ap; + + for (ap = ap_proxies; ap->apr_p; ap++) + if ((ap->apr_p == pr) && + !strncmp(name, ap->apr_label, sizeof(ap->apr_label))) + return ap; + return NULL; +} + + +void ap_free(ap) +aproxy_t *ap; +{ + KFREE(ap); +} + + +void aps_free(aps) +ap_session_t *aps; +{ + if (aps->aps_data && aps->aps_psiz) + KFREES(aps->aps_data, aps->aps_psiz); + KFREE(aps); +} + + +void ap_unload() +{ + ap_session_t *aps; + int i; + + for (i = 0; i < AP_SESS_SIZE; i++) + while (aps = ap_sess_tab[i]) { + ap_sess_tab[i] = aps->aps_next; + aps_free(aps); + } +} diff --git a/contrib/ipfilter/ip_proxy.h b/contrib/ipfilter/ip_proxy.h new file mode 100644 index 00000000000..2d7175491b3 --- /dev/null +++ b/contrib/ipfilter/ip_proxy.h @@ -0,0 +1,89 @@ +/* + * (C)opyright 1997 by Darren Reed. + * + * Redistribution and use in source and binary forms are permitted + * provided that this notice is preserved and due credit is given + * to the original author and the contributors. + * + * $Id: ip_proxy.h,v 2.0.2.2 1997/05/24 07:36:44 darrenr Exp $ + */ + +#ifndef __IP_PROXY_H__ +#define __IP_PROXY_H__ + +#ifndef SOLARIS +#define SOLARIS (defined(sun) && (defined(__svr4__) || defined(__SVR4))) +#endif + +#define APR_LABELLEN 16 +#define AP_SESS_SIZE 53 + +struct nat; + +typedef struct ap_tcp { + u_short apt_sport; /* source port */ + u_short apt_dport; /* destination port */ + short apt_seqoff; /* sequence # difference */ + short apt_ackoff; /* ack # difference */ + tcp_seq apt_after; /* don't change seq-off until after this */ + char apt_state[2]; /* connection state */ +} ap_tcp_t; + +typedef struct ap_udp { + u_short apu_sport; /* source port */ + u_short apu_dport; /* destination port */ +} ap_udp_t; + +typedef struct ap_session { + struct aproxy *aps_apr; + struct in_addr aps_src; /* source IP# */ + struct in_addr aps_dst; /* destination IP# */ + u_char aps_p; /* protocol */ + union { + struct ap_tcp apu_tcp; + struct ap_udp apu_udp; + } aps_un; + u_int aps_flags; + QUAD_T aps_bytes; /* bytes sent */ + QUAD_T aps_pkts; /* packets sent */ + time_t aps_tout; /* time left before expiring */ + void *aps_data; /* private data */ + int aps_psiz; /* size of private data */ + struct ap_session *aps_next; +} ap_session_t ; + +#define aps_sport aps_un.apu_tcp.apt_sport +#define aps_dport aps_un.apu_tcp.apt_dport +#define aps_seqoff aps_un.apu_tcp.apt_seqoff +#define aps_ackoff aps_un.apu_tcp.apt_ackoff +#define aps_sumoff aps_un.apu_tcp.apt_sumoff +#define aps_state aps_un.apu_tcp.apt_state +#define aps_after aps_un.apu_tcp.apt_after + + +typedef struct aproxy { + char apr_label[APR_LABELLEN]; /* Proxy label # */ + char apr_p; /* protocol */ + int apr_ref; /* +1 per rule referencing it */ + int apr_flags; + int (* apr_init) __P((fr_info_t *, ip_t *, tcphdr_t *, + ap_session_t *, struct nat *)); + int (* apr_inpkt) __P((fr_info_t *, ip_t *, tcphdr_t *, + ap_session_t *, struct nat *)); + int (* apr_outpkt) __P((fr_info_t *, ip_t *, tcphdr_t *, + ap_session_t *, struct nat *)); +} aproxy_t; + +#define APR_DELETE 1 + + +extern ap_session_t *ap_sess_tab[AP_SESS_SIZE]; +extern aproxy_t ap_proxies[]; + +extern void ap_unload __P((void)); +extern void ap_free __P((aproxy_t *)); +extern void aps_free __P((ap_session_t *)); +extern int ap_check __P((ip_t *, tcphdr_t *, fr_info_t *, struct nat *)); +extern aproxy_t *ap_match __P((char, char *)); + +#endif /* __IP_PROXY_H__ */