From: kjell Date: Wed, 5 Apr 2000 05:35:27 +0000 (+0000) Subject: Update to ipf 3.3.12. Most fixes relate to hardening of X-Git-Url: http://artulab.com/gitweb/?a=commitdiff_plain;h=27b5a4af0aeecc8ca7293f2c00c9c23ef9537b1f;p=openbsd Update to ipf 3.3.12. Most fixes relate to hardening of in-kernel ftp proxy. See sbin/ipf/HISTORY for details. --- diff --git a/sbin/ipf/HISTORY b/sbin/ipf/HISTORY index 84b5927fe03..bd61b940507 100644 --- a/sbin/ipf/HISTORY +++ b/sbin/ipf/HISTORY @@ -1,4 +1,4 @@ -# $OpenBSD: HISTORY,v 1.5 2000/03/13 23:40:19 kjell Exp $ +# $OpenBSD: HISTORY,v 1.6 2000/04/05 05:35:28 kjell Exp $ # # NOTE: Quite a few patches and suggestions come from other sources, to whom # I'm greatly indebted, even if no names are mentioned. @@ -21,6 +21,19 @@ # and especially those who have found the time to port IP Filter to new # platforms. # +3.3.12 16/03/2000 - Released + +tighten up ftp proxy behaviour. sigh. yuck. hate. + +fix bug in range check for NAT where the last IP# was not used. + +fix problem with icmp codes > 127 in filter rules caused bad things to +happen and in particular, where #18 caused the rule to be printed +erroneously. + +fix bug with the spl level not being reset when returning EIO from +iplioctl due to ipfilter not being initialized yet. + 3.3.11 04/03/2000 - Released make "or-block" work with lines that start with "log" diff --git a/sbin/ipf/ifaddr.c b/sbin/ipf/ifaddr.c index e34116d5feb..3f162c361a3 100644 --- a/sbin/ipf/ifaddr.c +++ b/sbin/ipf/ifaddr.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ifaddr.c,v 1.4 2000/03/13 23:40:19 kjell Exp $ */ +/* $OpenBSD: ifaddr.c,v 1.5 2000/04/05 05:35:28 kjell Exp $ */ #include #include #include diff --git a/sbin/ipf/ifaddr.h b/sbin/ipf/ifaddr.h index 8810aac2d78..bb882dcddf7 100644 --- a/sbin/ipf/ifaddr.h +++ b/sbin/ipf/ifaddr.h @@ -1,4 +1,4 @@ -/* $OpenBSD: ifaddr.h,v 1.4 2000/03/13 23:40:19 kjell Exp $ */ +/* $OpenBSD: ifaddr.h,v 1.5 2000/04/05 05:35:28 kjell Exp $ */ #ifndef __IFADDR_H__ #define __IFADDR_H__ diff --git a/sbin/ipf/parse.c b/sbin/ipf/parse.c index 819618680d8..8b3e04f1027 100644 --- a/sbin/ipf/parse.c +++ b/sbin/ipf/parse.c @@ -1,4 +1,4 @@ -/* $OpenBSD: parse.c,v 1.33 2000/03/13 23:40:19 kjell Exp $ */ +/* $OpenBSD: parse.c,v 1.34 2000/04/05 05:35:28 kjell Exp $ */ /* * Copyright (C) 1993-1998 by Darren Reed. @@ -43,7 +43,7 @@ #if !defined(lint) static const char sccsid[] = "@(#)parse.c 1.44 6/5/96 (C) 1993-1996 Darren Reed"; -static const char rcsid[] = "@(#)$IPFilter: parse.c,v 2.1.2.11 2000/03/04 05:19:25 darrenr Exp $"; +static const char rcsid[] = "@(#)$IPFilter: parse.c,v 2.1.2.12 2000/03/08 11:43:55 darrenr Exp $"; #endif extern struct ipopt_names ionames[], secclass[]; @@ -1560,7 +1560,7 @@ struct frentry *fp; type = ntohs(fp->fr_icmp); code = type & 0xff; type /= 256; - if (type < (sizeof(icmptypes) / sizeof(char *)) && + if (type < (sizeof(icmptypes) / sizeof(char *) - 1) && icmptypes[type]) printf(" icmp-type %s", icmptypes[type]); else diff --git a/sys/netinet/ip_fil.c b/sys/netinet/ip_fil.c index 42370ca6fb7..ce1a3435d81 100644 --- a/sys/netinet/ip_fil.c +++ b/sys/netinet/ip_fil.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ip_fil.c,v 1.32 2000/03/13 23:40:17 kjell Exp $ */ +/* $OpenBSD: ip_fil.c,v 1.33 2000/04/05 05:35:27 kjell Exp $ */ /* * Copyright (C) 1993-1998 by Darren Reed. @@ -9,7 +9,7 @@ */ #if !defined(lint) static const char sccsid[] = "@(#)ip_fil.c 2.41 6/5/96 (C) 1993-1995 Darren Reed"; -static const char rcsid[] = "@(#)$IPFilter: ip_fil.c,v 2.4.2.18 2000/02/22 11:40:06 darrenr Exp $"; +static const char rcsid[] = "@(#)$IPFilter: ip_fil.c,v 2.4.2.19 2000/03/07 14:41:39 darrenr Exp $"; #endif #ifndef SOLARIS @@ -472,19 +472,23 @@ int mode; SPL_NET(s); if (unit == IPL_LOGNAT) { - if (!fr_running) - return EIO; - error = nat_ioctl(data, cmd, mode); + if (fr_running) + error = nat_ioctl(data, cmd, mode); + else + error = EIO; SPL_X(s); return error; } + if (unit == IPL_LOGSTATE) { - if (!fr_running) - return EIO; - error = fr_state_ioctl(data, cmd, mode); + if (fr_running) + error = fr_state_ioctl(data, cmd, mode); + else + error = EIO; SPL_X(s); return error; } + switch (cmd) { case FIONREAD : #ifdef IPFILTER_LOG diff --git a/sys/netinet/ip_fil.h b/sys/netinet/ip_fil.h index 0659077f953..9a0dcd92207 100644 --- a/sys/netinet/ip_fil.h +++ b/sys/netinet/ip_fil.h @@ -1,4 +1,4 @@ -/* $OpenBSD: ip_fil.h,v 1.17 2000/03/13 23:40:17 kjell Exp $ */ +/* $OpenBSD: ip_fil.h,v 1.18 2000/04/05 05:35:27 kjell Exp $ */ /* * Copyright (C) 1993-1998 by Darren Reed. @@ -8,7 +8,7 @@ * to the original author and the contributors. * * @(#)ip_fil.h 1.35 6/5/96 - * $IPFilter: ip_fil.h,v 2.3.2.8 2000/02/23 11:16:36 darrenr Exp $ + * $IPFilter: ip_fil.h,v 2.3.2.9 2000/03/08 11:43:30 darrenr Exp $ */ #ifndef __IP_FIL_H__ @@ -187,7 +187,7 @@ typedef struct frentry { u_short fr_skip; /* # of rules to skip */ u_short fr_loglevel; /* syslog log facility + priority */ int (*fr_func) __P((int, ip_t *, fr_info_t *)); /* call this function */ - char fr_icode; /* return ICMP code */ + u_char fr_icode; /* return ICMP code */ char fr_ifname[IFNAMSIZ]; #if BSD >= 199306 char fr_oifname[IFNAMSIZ]; diff --git a/sys/netinet/ip_fil_compat.h b/sys/netinet/ip_fil_compat.h index 0ad32f2315f..a23220edb29 100644 --- a/sys/netinet/ip_fil_compat.h +++ b/sys/netinet/ip_fil_compat.h @@ -1,4 +1,4 @@ -/* $OpenBSD: ip_fil_compat.h,v 1.14 2000/03/13 23:40:18 kjell Exp $ */ +/* $OpenBSD: ip_fil_compat.h,v 1.15 2000/04/05 05:35:27 kjell Exp $ */ /* * Copyright (C) 1993-1998 by Darren Reed. diff --git a/sys/netinet/ip_ftp_pxy.c b/sys/netinet/ip_ftp_pxy.c index 8080ad9f28f..ab947e72aa8 100644 --- a/sys/netinet/ip_ftp_pxy.c +++ b/sys/netinet/ip_ftp_pxy.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ip_ftp_pxy.c,v 1.8 2000/03/13 23:40:18 kjell Exp $ */ +/* $OpenBSD: ip_ftp_pxy.c,v 1.9 2000/04/05 05:35:27 kjell Exp $ */ /* * Simple FTP transparent proxy for in-kernel use. For use with the NAT @@ -9,6 +9,7 @@ extern kmutex_t ipf_rw; #endif #define isdigit(x) ((x) >= '0' && (x) <= '9') +#define isupper(x) ((unsigned)((x) - 'A') <= 'Z' - 'A') #define IPF_FTP_PROXY @@ -16,17 +17,23 @@ extern kmutex_t ipf_rw; #define IPF_MAXPORTLEN 30 #define IPF_MIN227LEN 39 #define IPF_MAX227LEN 51 +#define IPF_FTPBUFSZ MAX(68,IPF_MAX227LEN) /* This *MUST* be >= 51! */ + /* 68 is chosen as the minimum datagram size for */ + /* an unfragmented packet */ int ippr_ftp_init __P((void)); +int ippr_ftp_new __P((fr_info_t *, ip_t *, ap_session_t *, nat_t *)); int ippr_ftp_out __P((fr_info_t *, ip_t *, ap_session_t *, nat_t *)); int ippr_ftp_in __P((fr_info_t *, ip_t *, ap_session_t *, nat_t *)); int ippr_ftp_portmsg __P((fr_info_t *, ip_t *, nat_t *)); int ippr_ftp_pasvmsg __P((fr_info_t *, ip_t *, nat_t *)); +int ippr_ftp_complete __P((char *, size_t)); u_short ipf_ftp_atoi __P((char **)); static frentry_t natfr; +int ippr_ftp_pasvonly = 0; /* @@ -41,6 +48,90 @@ int ippr_ftp_init() } +int ippr_ftp_complete(buf, len) +char *buf; +size_t len; +{ + register char *s, c; + register size_t i; + + if (len < 5) + return -1; + s = buf; + c = *s++; + i = len - 1; + + if (isdigit(c)) { + c = *s++; + i--; + if (isdigit(c)) { + c = *s++; + i--; + if (isdigit(c)) { + c = *s++; + i--; + if (c != '-' && c != ' ') + return -1; + } else + return -1; + } else + return -1; + } else if (isupper(c)) { + c = *s++; + i--; + if (isupper(c)) { + c = *s++; + i--; + if (isupper(c)) { + c = *s++; + i--; + if (isupper(c)) { + c = *s++; + i--; + if (c != ' ') + return -1; + } else + return -1; + } else + return -1; + } else + return -1; + } else + return -1; + + for (; i && (c = *s); i--, s++) { + if ((c == '\r') && (i != 2)) + return -1; + if ((c == '\n') && (i != 1)) + return -1; + else if ((i == 2) && (c != '\r')) + return -1; + else if ((i == 1) && (c != '\n')) + return -1; + } + return i; +} + + +int ippr_ftp_new(fin, ip, aps, nat) +fr_info_t *fin; +ip_t *ip; +ap_session_t *aps; +nat_t *nat; +{ + ftpinfo_t *ftp; + + KMALLOC(ftp, ftpinfo_t *); + if (ftp == NULL) + return -1; + aps->aps_data = ftp; + aps->aps_psiz = sizeof(ftpinfo_t); + + ftp->ftp_passok = 0; + return 0; +} + + /* * ipf_ftp_atoi - implement a version of atoi which processes numbers in * pairs separated by commas (which are expected to be in the range 0 - 255), @@ -75,13 +166,14 @@ fr_info_t *fin; ip_t *ip; nat_t *nat; { - char portbuf[IPF_MAXPORTLEN + 1], newbuf[IPF_MAXPORTLEN + 1], *s; + char portbuf[IPF_FTPBUFSZ], newbuf[IPF_FTPBUFSZ], *s; tcphdr_t *tcp, tcph, *tcp2 = &tcph; size_t nlen = 0, dlen, olen; u_short a5, a6, sp, dp; u_int a1, a2, a3, a4; struct in_addr swip; int off, inc = 0; + ftpinfo_t *ftp; fr_info_t fi; nat_t *ipn; mb_t *m; @@ -110,7 +202,30 @@ nat_t *nat; return 0; portbuf[sizeof(portbuf) - 1] = '\0'; *newbuf = '\0'; - if (!strncmp(portbuf, "PORT ", 5)) { + + /* + * Check that a user is progressing through the login ok. + */ + if (ippr_ftp_complete(portbuf, dlen)) + return 0; + ftp = nat->nat_aps->aps_data; + switch (ftp->ftp_passok) + { + case 0 : + if (!strncmp(portbuf, "USER ", 5)) + ftp->ftp_passok = 1; + break; + case 2 : + if (!strncmp(portbuf, "PASS ", 5)) + ftp->ftp_passok = 3; + break; + } + if (ftp->ftp_passok != 4) + return 0; + /* + * Check for client sending out PORT message. + */ + if (!ippr_ftp_pasvonly && !strncmp(portbuf, "PORT ", 5)) { if (dlen < IPF_MINPORTLEN) return 0; } else @@ -165,6 +280,7 @@ nat_t *nat; a4 = a1 & 0xff; a1 >>= 24; olen = s - portbuf; + /* DO NOT change this to sprintf! */ (void) sprintf(newbuf, "%s %u,%u,%u,%u,%u,%u\r\n", "PORT", a1, a2, a3, a4, a5, a6); @@ -224,6 +340,12 @@ nat_t *nat; * other way. */ sp = htons(a5 << 8 | a6); + /* + * Don't allow the PORT command to specify a port < 1024 due to + * security crap. + */ + if (ntohs(sp) < 1024) + return 0; /* * The server may not make the connection back from port 20, but * it is the most likely so use it here to check for a conflicting @@ -270,12 +392,13 @@ fr_info_t *fin; ip_t *ip; nat_t *nat; { - char portbuf[IPF_MAX227LEN + 1], newbuf[IPF_MAX227LEN + 1], *s; + char portbuf[IPF_FTPBUFSZ], newbuf[IPF_FTPBUFSZ], *s; int off, olen, dlen, nlen = 0, inc = 0; tcphdr_t tcph, *tcp2 = &tcph; struct in_addr swip, swip2; u_short a5, a6, dp, sp; u_int a1, a2, a3, a4; + ftpinfo_t *ftp; tcphdr_t *tcp; fr_info_t fi; nat_t *ipn; @@ -305,6 +428,35 @@ nat_t *nat; portbuf[sizeof(portbuf) - 1] = '\0'; *newbuf = '\0'; + /* + * Check that a user is progressing through the login ok. + * Don't put the switch in one common function because one side + * should only see numeric responses and the other commands. + */ + if (ippr_ftp_complete(portbuf, dlen)) + return 0; + ftp = nat->nat_aps->aps_data; + switch (ftp->ftp_passok) + { + case 1 : + if (!strncmp(portbuf, "331", 3)) + ftp->ftp_passok = 2; + else if (!strncmp(portbuf, "520", 3)) + ftp->ftp_passok = 0; + break; + case 3 : + if (!strncmp(portbuf, "230", 3)) + ftp->ftp_passok = 4; + break; + default : + break; + } + + if (ftp->ftp_passok != 4) + return 0; + /* + * Check for PASV reply message. + */ if (!strncmp(portbuf, "227 ", 4)) { if (dlen < IPF_MIN227LEN) return 0; diff --git a/sys/netinet/ip_nat.c b/sys/netinet/ip_nat.c index 49b19127dee..d0237d43c49 100644 --- a/sys/netinet/ip_nat.c +++ b/sys/netinet/ip_nat.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ip_nat.c,v 1.28 2000/03/13 23:40:18 kjell Exp $ */ +/* $OpenBSD: ip_nat.c,v 1.29 2000/04/05 05:35:27 kjell Exp $ */ /* * Copyright (C) 1995-1998 by Darren Reed. @@ -11,7 +11,7 @@ */ #if !defined(lint) static const char sccsid[] = "@(#)ip_nat.c 1.11 6/5/96 (C) 1995 Darren Reed"; -static const char rcsid[] = "@(#)$IPFilter: ip_nat.c,v 2.2.2.12 2000/01/24 12:43:40 darrenr Exp $"; +static const char rcsid[] = "@(#)$IPFilter: ip_nat.c,v 2.2.2.13 2000/03/08 14:17:26 darrenr Exp $"; #endif #if defined(__FreeBSD__) && defined(KERNEL) && !defined(_KERNEL) @@ -859,7 +859,7 @@ int direction; } if (np->in_flags & IPN_RANGE) { - if (np->in_nip >= ntohl(np->in_outmsk)) + if (np->in_nip > ntohl(np->in_outmsk)) np->in_nip = ntohl(np->in_outip); } else { if ((np->in_outmsk != 0xffffffff) && diff --git a/sys/netinet/ip_nat.h b/sys/netinet/ip_nat.h index 09fb932be9b..9d126294ba9 100644 --- a/sys/netinet/ip_nat.h +++ b/sys/netinet/ip_nat.h @@ -1,4 +1,4 @@ -/* $OpenBSD: ip_nat.h,v 1.16 2000/03/13 23:40:18 kjell Exp $ */ +/* $OpenBSD: ip_nat.h,v 1.17 2000/04/05 05:35:27 kjell Exp $ */ /* * Copyright (C) 1995-1998 by Darren Reed. @@ -8,7 +8,7 @@ * to the original author and the contributors. * * @(#)ip_nat.h 1.5 2/4/96 - * $IPFilter: ip_nat.h,v 2.1.2.3 2000/01/24 12:44:24 darrenr Exp $ + * $IPFilter: ip_nat.h,v 2.1.2.4 2000/03/15 13:57:03 darrenr Exp $ */ #ifndef __IP_NAT_H__ @@ -63,14 +63,16 @@ #define DEF_NAT_AGE 1200 /* 10 minutes (600 seconds) */ +struct ap_session; + typedef struct nat { u_long nat_age; int nat_flags; u_32_t nat_sumd[2]; u_32_t nat_ipsumd; void *nat_data; - void *nat_aps; /* proxy session */ - frentry_t *nat_fr; /* filter rule ptr if appropriate */ + struct ap_session *nat_aps; /* proxy session */ + struct frentry *nat_fr; /* filter rule ptr if appropriate */ struct in_addr nat_inip; struct in_addr nat_outip; struct in_addr nat_oip; /* other ip */ diff --git a/sys/netinet/ip_proxy.c b/sys/netinet/ip_proxy.c index bb3f623bff5..2184909d792 100644 --- a/sys/netinet/ip_proxy.c +++ b/sys/netinet/ip_proxy.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ip_proxy.c,v 1.8 2000/03/13 23:40:18 kjell Exp $ */ +/* $OpenBSD: ip_proxy.c,v 1.9 2000/04/05 05:35:27 kjell Exp $ */ /* * Copyright (C) 1997-1998 by Darren Reed. @@ -8,7 +8,7 @@ * to the original author and the contributors. */ #if !defined(lint) -static const char rcsid[] = "@(#)$IPFilter: ip_proxy.c,v 2.2.2.3 2000/02/29 22:47:17 darrenr Exp $"; +static const char rcsid[] = "@(#)$IPFilter: ip_proxy.c,v 2.2.2.4 2000/03/15 13:57:53 darrenr Exp $"; #endif #if defined(__FreeBSD__) && defined(KERNEL) && !defined(_KERNEL) @@ -102,8 +102,8 @@ ap_session_t *ap_sess_tab[AP_SESS_SIZE]; ap_session_t *ap_sess_list = NULL; aproxy_t ap_proxies[] = { #ifdef IPF_FTP_PROXY - { "ftp", (char)IPPROTO_TCP, 0, 0, ippr_ftp_init, NULL, NULL, - ippr_ftp_in, ippr_ftp_out }, + { "ftp", (char)IPPROTO_TCP, 0, 0, ippr_ftp_init, NULL, + ippr_ftp_new, ippr_ftp_in, ippr_ftp_out }, #endif #ifdef IPF_RCMD_PROXY { "rcmd", (char)IPPROTO_TCP, 0, 0, ippr_rcmd_init, NULL, @@ -154,16 +154,18 @@ nat_t *nat; if (!aps) return NULL; bzero((char *)aps, sizeof(*aps)); - aps->aps_next = ap_sess_list; aps->aps_p = ip->ip_p; aps->aps_data = NULL; aps->aps_apr = apr; aps->aps_psiz = 0; - ap_sess_list = aps; - aps->aps_nat = nat; - nat->nat_aps = aps; if (apr->apr_new != NULL) - (void) (*apr->apr_new)(fin, ip, aps, nat); + if ((*apr->apr_new)(fin, ip, aps, nat) == -1) { + KFREE(aps); + return NULL; + } + aps->aps_nat = nat; + aps->aps_next = ap_sess_list; + ap_sess_list = aps; return aps; } diff --git a/sys/netinet/ip_proxy.h b/sys/netinet/ip_proxy.h index 204ca733ac2..f20e8b9d566 100644 --- a/sys/netinet/ip_proxy.h +++ b/sys/netinet/ip_proxy.h @@ -1,4 +1,4 @@ -/* $OpenBSD: ip_proxy.h,v 1.7 2000/03/13 23:40:18 kjell Exp $ */ +/* $OpenBSD: ip_proxy.h,v 1.8 2000/04/05 05:35:27 kjell Exp $ */ /* * Copyright (C) 1997-1998 by Darren Reed. @@ -7,7 +7,7 @@ * provided that this notice is preserved and due credit is given * to the original author and the contributors. * - * $IPFilter: ip_proxy.h,v 2.1.2.2 2000/02/22 11:41:15 darrenr Exp $ + * $IPFilter: ip_proxy.h,v 2.1.2.3 2000/03/15 13:58:15 darrenr Exp $ */ #ifndef __IP_PROXY_H__ @@ -86,6 +86,13 @@ typedef struct aproxy { #define APR_DELETE 1 +/* + * For the ftp proxy. + */ +typedef struct ftpinfo { + u_int ftp_passok; +} ftpinfo_t; + /* * Real audio proxy structure and #defines */ diff --git a/sys/netinet/ip_raudio_pxy.c b/sys/netinet/ip_raudio_pxy.c index f43e05b1370..4f1eb26ff43 100644 --- a/sys/netinet/ip_raudio_pxy.c +++ b/sys/netinet/ip_raudio_pxy.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ip_raudio_pxy.c,v 1.6 2000/03/13 23:40:18 kjell Exp $ */ +/* $OpenBSD: ip_raudio_pxy.c,v 1.7 2000/04/05 05:35:27 kjell Exp $ */ #if SOLARIS && defined(_KERNEL) extern kmutex_t ipf_rw; @@ -40,12 +40,13 @@ nat_t *nat; KMALLOCS(aps->aps_data, void *, sizeof(raudio_t)); - if (aps->aps_data != NULL) { - bzero(aps->aps_data, sizeof(raudio_t)); - rap = aps->aps_data; - aps->aps_psiz = sizeof(raudio_t); - rap->rap_mode = RAP_M_TCP; /* default is for TCP */ - } + if (aps->aps_data == NULL) + return -1; + + bzero(aps->aps_data, sizeof(raudio_t)); + rap = aps->aps_data; + aps->aps_psiz = sizeof(raudio_t); + rap->rap_mode = RAP_M_TCP; /* default is for TCP */ return 0; } diff --git a/sys/netinet/ipl.h b/sys/netinet/ipl.h index dbde9998e62..50e8ae094ed 100644 --- a/sys/netinet/ipl.h +++ b/sys/netinet/ipl.h @@ -1,4 +1,4 @@ -/* $OpenBSD: ipl.h,v 1.6 2000/03/13 23:40:18 kjell Exp $ */ +/* $OpenBSD: ipl.h,v 1.7 2000/04/05 05:35:27 kjell Exp $ */ /* * Copyright (C) 1993-1999 by Darren Reed. @@ -13,6 +13,6 @@ #ifndef __IPL_H__ #define __IPL_H__ -#define IPL_VERSION "IP Filter: v3.3.11" +#define IPL_VERSION "IP Filter: v3.3.12" #endif