diff -ur tcp_wrappers_7.6.orig/fix_options.c tcp_wrappers_7.6/fix_options.c --- tcp_wrappers_7.6.orig/fix_options.c Tue Apr 8 04:29:19 1997 +++ tcp_wrappers_7.6/fix_options.c Mon Oct 2 06:04:58 2000 @@ -11,6 +11,7 @@ #include #include +#include #include #include #include @@ -29,80 +30,59 @@ /* fix_options - get rid of IP-level socket options */ +void fix_options(request) struct request_info *request; { #ifdef IP_OPTIONS - unsigned char optbuf[BUFFER_SIZE / 3], *cp; - char lbuf[BUFFER_SIZE], *lp; + struct ip_options optbuf; + char lbuf[BUFFER_SIZE], *lp, *cp; int optsize = sizeof(optbuf), ipproto; struct protoent *ip; int fd = request->fd; - unsigned int opt; - int optlen; - struct in_addr dummy; + int i; if ((ip = getprotobyname("ip")) != 0) ipproto = ip->p_proto; else ipproto = IPPROTO_IP; - if (getsockopt(fd, ipproto, IP_OPTIONS, (char *) optbuf, &optsize) == 0 + if (getsockopt(fd, ipproto, IP_OPTIONS, (char *) &optbuf, &optsize) == 0 && optsize != 0) { /* - * Horror! 4.[34] BSD getsockopt() prepends the first-hop destination - * address to the result IP options list when source routing options - * are present (see ), but produces no output for - * other IP options. Solaris 2.x getsockopt() does produce output for - * non-routing IP options, and uses the same format as BSD even when - * the space for the destination address is unused. The code below - * does the right thing with 4.[34]BSD derivatives and Solaris 2, but - * may occasionally miss source routing options on incompatible - * systems such as Linux. Their choice. - * - * Look for source routing options. Drop the connection when one is - * found. Just wiping the IP options is insufficient: we would still - * help the attacker by providing a real TCP sequence number, and the - * attacker would still be able to send packets (blind spoofing). I - * discussed this attack with Niels Provos, half a year before the - * attack was described in open mailing lists. - * - * It would be cleaner to just return a yes/no reply and let the caller - * decide how to deal with it. Resident servers should not terminate. - * However I am not prepared to make changes to internal interfaces - * on short notice. + * Properly deal with source routing entries. The original code + * here was wrong. + * + * This replacement code is OpenBSD-derived, but ported to Linux + * (struct ipoption vs. struct ip_options). Most systems will have + * source-routed packets disallowed in the kernel, so this is of + * little importance now. */ -#define ADDR_LEN sizeof(dummy.s_addr) - - for (cp = optbuf + ADDR_LEN; cp < optbuf + optsize; cp += optlen) { - opt = cp[IPOPT_OPTVAL]; - if (opt == IPOPT_LSRR || opt == IPOPT_SSRR) { - syslog(LOG_WARNING, - "refused connect from %s with IP source routing options", - eval_client(request)); - shutdown(fd, 2); - return; - } - if (opt == IPOPT_EOL) - break; - if (opt == IPOPT_NOP) { - optlen = 1; - } else { - optlen = cp[IPOPT_OLEN]; - if (optlen <= 0) /* Do not loop! */ - break; - } + for (i = 0; (void *)&optbuf.__data[i] - (void *)&optbuf < + optsize; ) { + u_char c = (u_char)optbuf.__data[i]; + if (c == IPOPT_LSRR || c == IPOPT_SSRR) { + syslog(LOG_WARNING, + "refused connect from %s with IP source routing options", + eval_client(request)); + clean_exit(request); + } + if (c == IPOPT_EOL) + break; + i += (c == IPOPT_NOP) ? 1 : (u_char)optbuf.__data[i+1]; } + lp = lbuf; - for (cp = optbuf; optsize > 0; cp++, optsize--, lp += 3) - sprintf(lp, " %2.2x", *cp); + for (cp = (char *)&optbuf; optsize > 0 && lp < &lbuf[sizeof lbuf-1]; + cp++, optsize--, lp += 3) + sprintf(lp, " %2.2x", *cp); syslog(LOG_NOTICE, "connect from %s with IP options (ignored):%s", eval_client(request), lbuf); if (setsockopt(fd, ipproto, IP_OPTIONS, (char *) 0, optsize) != 0) { syslog(LOG_ERR, "setsockopt IP_OPTIONS NULL: %m"); - shutdown(fd, 2); + clean_exit(request); } } #endif