## Automatically generated incremental diff ## From: linux-2.0.37-pre11 ## To: linux-2.0.37-pre12 ## Robot: $Id: make-incremental-diff,v 1.11 2002/02/20 02:59:33 hpa Exp $ diff -urN linux-2.0.37-pre11/arch/i386/kernel/sys_i386.c linux-2.0.37-pre12/arch/i386/kernel/sys_i386.c --- linux-2.0.37-pre11/arch/i386/kernel/sys_i386.c 2003-08-15 15:04:50.000000000 -0700 +++ linux-2.0.37-pre12/arch/i386/kernel/sys_i386.c 1996-04-11 23:49:30.000000000 -0700 @@ -48,23 +48,19 @@ int error; unsigned long flags; struct file * file = NULL; - unsigned long b[6]; error = verify_area(VERIFY_READ, buffer, 6*sizeof(long)); if (error) return error; - memcpy_fromfs(&b[0], buffer, 6*sizeof(long)); - flags = b[3]; + flags = get_user(buffer+3); if (!(flags & MAP_ANONYMOUS)) { - unsigned long fd = b[4]; + unsigned long fd = get_user(buffer+4); if (fd >= NR_OPEN || !(file = current->files->fd[fd])) return -EBADF; } flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE); - down(¤t->mm->mmap_sem); - error = do_mmap(file, b[0], b[1], b[2], flags, b[5]); - up(¤t->mm->mmap_sem); - return error; + return do_mmap(file, get_user(buffer), get_user(buffer+1), + get_user(buffer+2), flags, get_user(buffer+5)); } extern asmlinkage int sys_select(int, fd_set *, fd_set *, fd_set *, struct timeval *); diff -urN linux-2.0.37-pre11/CREDITS linux-2.0.37-pre12/CREDITS --- linux-2.0.37-pre11/CREDITS 2003-08-15 15:04:50.000000000 -0700 +++ linux-2.0.37-pre12/CREDITS 2003-08-15 15:04:50.000000000 -0700 @@ -557,6 +557,14 @@ S: Atlanta, Georgia 30332 S: USA +N: John Hardin +E: jhardin@wolfenet.com +W: http://www.wolfenet.com/~jhardin/ +D: IPSec and PPTP masquerade +S: 17014 Broadway ave. +S: Snohomish, WA 98296-8031 +S: USA + N: Angelo Haritsis E: ah@doc.ic.ac.uk D: kernel patches (serial, watchdog) diff -urN linux-2.0.37-pre11/drivers/block/floppy.c linux-2.0.37-pre12/drivers/block/floppy.c --- linux-2.0.37-pre11/drivers/block/floppy.c 2003-08-15 15:04:50.000000000 -0700 +++ linux-2.0.37-pre12/drivers/block/floppy.c 2003-08-15 15:04:50.000000000 -0700 @@ -601,7 +601,7 @@ drive = current_drive; del_timer(&fd_timeout); if (drive < 0 || drive > N_DRIVE) { - fd_timeout.expires = jiffies + 20*HZ; + fd_timeout.expires = jiffies + 20UL*HZ; drive=0; } else fd_timeout.expires = jiffies + UDP->timeout; @@ -969,7 +969,7 @@ } /* waits for a delay (spinup or select) to pass */ -static int wait_for_completion(int delay, timeout_fn function) +static int wait_for_completion(unsigned long delay, timeout_fn function) { if (FDCS->reset){ reset_fdc(); /* do the reset during sleep to win time @@ -1318,7 +1318,7 @@ * Pause 5 msec to avoid trouble. (Needs to be 2 jiffies) */ FDCS->dtr = raw_cmd->rate & 3; - return(wait_for_completion(jiffies+2*HZ/100, + return(wait_for_completion(jiffies+2UL*HZ/100, (timeout_fn) floppy_ready)); } /* fdc_dtr */ @@ -2903,7 +2903,7 @@ * Misc Ioctl's and support * ======================== */ -static int fd_copyout(void *param, const void *address, int size) +static int fd_copyout(void *param, const void *address, unsigned long size) { int ret; @@ -2912,7 +2912,7 @@ return 0; } -static int fd_copyin(void *param, void *address, int size) +static int fd_copyin(void *param, void *address, unsigned long size) { int ret; diff -urN linux-2.0.37-pre11/drivers/net/eql.c linux-2.0.37-pre12/drivers/net/eql.c --- linux-2.0.37-pre11/drivers/net/eql.c 2003-08-15 15:04:50.000000000 -0700 +++ linux-2.0.37-pre12/drivers/net/eql.c 2003-08-15 15:04:50.000000000 -0700 @@ -389,8 +389,8 @@ eql_schedule_slaves (eql->queue); - slave_dev = eql_best_slave_dev (eql->queue); slave = eql_best_slave (eql->queue); + slave_dev = slave ? slave->dev : 0; if ( slave_dev != 0 ) { diff -urN linux-2.0.37-pre11/fs/locks.c linux-2.0.37-pre12/fs/locks.c --- linux-2.0.37-pre11/fs/locks.c 1998-11-15 10:33:13.000000000 -0800 +++ linux-2.0.37-pre12/fs/locks.c 2003-08-15 15:04:50.000000000 -0700 @@ -107,6 +107,7 @@ #include #include #include +#include #include #include @@ -255,17 +256,25 @@ { struct file_lock file_lock; struct file *filp; - - if ((fd >= NR_OPEN) || !(filp = current->files->fd[fd])) - return (-EBADF); + int err = -EINVAL; + + filp = fget(fd); + if(filp==NULL) + return -EBADF; + if (!flock_make_lock(filp, &file_lock, cmd)) - return (-EINVAL); - - if ((file_lock.fl_type != F_UNLCK) && !(filp->f_mode & 3)) - return (-EBADF); + goto out; - return (flock_lock_file(filp, &file_lock, (cmd & (LOCK_UN | LOCK_NB)) ? 0 : 1)); + if ((file_lock.fl_type != F_UNLCK) && !(filp->f_mode & 3)) + { + err = -EBADF; + goto out; + } + err=flock_lock_file(filp, &file_lock, (cmd & (LOCK_UN | LOCK_NB)) ? 0 : 1); +out: + fput(filp, filp->f_inode); + return err; } /* Report the first existing lock that would conflict with l. @@ -278,19 +287,27 @@ struct file *filp; struct file_lock *fl,file_lock; - if ((fd >= NR_OPEN) || !(filp = current->files->fd[fd])) - return (-EBADF); error = verify_area(VERIFY_WRITE, l, sizeof(*l)); if (error) return (error); + filp = fget(fd); + if(filp==NULL) + return -EBADF; + memcpy_fromfs(&flock, l, sizeof(flock)); if ((flock.l_type != F_RDLCK) && (flock.l_type != F_WRLCK)) - return (-EINVAL); + { + error = -EINVAL; + goto out; + } if (!filp->f_inode || !posix_make_lock(filp, &file_lock, &flock)) - return (-EINVAL); - + { + error = -EINVAL; + goto out; + } + flock.l_type = F_UNLCK; for (fl = filp->f_inode->i_flock; fl != NULL; fl = fl->fl_next) { if (!(fl->fl_flags & FL_POSIX)) @@ -307,7 +324,9 @@ } memcpy_tofs(l, &flock, sizeof(flock)); - return (0); +out: + fput(filp, filp->f_inode); + return error; } /* Apply the lock described by l to an open file descriptor. @@ -326,19 +345,20 @@ /* Get arguments and validate them ... */ - if ((fd >= NR_OPEN) || !(filp = current->files->fd[fd])) - return (-EBADF); - error = verify_area(VERIFY_READ, l, sizeof(*l)); if (error) return (error); - - if (!(inode = filp->f_inode)) - return (-EINVAL); - + + filp = fget(fd); + if(filp==NULL) + return -EBADF; + + inode = filp->f_inode; + /* * This might block, so we do it before checking the inode. */ + memcpy_fromfs(&flock, l, sizeof(flock)); /* Don't allow mandatory locks on files that may be memory mapped @@ -350,22 +370,34 @@ struct vm_area_struct *vma = inode->i_mmap; do { if (vma->vm_flags & VM_MAYSHARE) - return (-EAGAIN); + { + error = -EAGAIN; + goto out; + } vma = vma->vm_next_share; } while (vma != inode->i_mmap); } if (!posix_make_lock(filp, &file_lock, &flock)) - return (-EINVAL); + { + error = -EINVAL; + goto out; + } switch (flock.l_type) { case F_RDLCK: if (!(filp->f_mode & 1)) - return (-EBADF); + { + error = -EBADF; + goto out; + } break; case F_WRLCK: if (!(filp->f_mode & 2)) - return (-EBADF); + { + error = -EBADF; + goto out; + } break; case F_UNLCK: break; @@ -384,13 +416,19 @@ } #endif if (!(filp->f_mode & 3)) - return (-EBADF); + { + error = -EBADF; + goto out; + } break; default: return (-EINVAL); } - return (posix_lock_file(filp, &file_lock, cmd == F_SETLKW)); + error = posix_lock_file(filp, &file_lock, cmd == F_SETLKW); +out: + fput(filp, filp->f_inode); + return error; } /* This function is called when the file is closed. diff -urN linux-2.0.37-pre11/fs/open.c linux-2.0.37-pre12/fs/open.c --- linux-2.0.37-pre11/fs/open.c 2003-08-15 15:04:50.000000000 -0700 +++ linux-2.0.37-pre12/fs/open.c 2003-08-15 15:04:50.000000000 -0700 @@ -68,11 +68,10 @@ int error; struct iattr newattrs; - /* Not pretty: "inode->i_size" shouldn't really be "off_t". But it is. */ if ((off_t) length < 0) return -EINVAL; - + down(&inode->i_sem); newattrs.ia_size = length; newattrs.ia_valid = ATTR_SIZE | ATTR_CTIME; diff -urN linux-2.0.37-pre11/fs/select.c linux-2.0.37-pre12/fs/select.c --- linux-2.0.37-pre11/fs/select.c 1998-11-15 10:33:14.000000000 -0800 +++ linux-2.0.37-pre12/fs/select.c 2003-08-15 15:04:50.000000000 -0700 @@ -347,10 +347,8 @@ (fd_set *) &res_out, (fd_set *) &res_ex, (fd_set *) &locked); - timeout = current->timeout - jiffies - 1; + timeout = current->timeout?current->timeout - jiffies - 1:0; current->timeout = 0; - if ((long) timeout < 0) - timeout = 0; if (tvp && !(current->personality & STICKY_TIMEOUTS)) { put_user(timeout/HZ, &tvp->tv_sec); timeout %= HZ; diff -urN linux-2.0.37-pre11/include/linux/in.h linux-2.0.37-pre12/include/linux/in.h --- linux-2.0.37-pre11/include/linux/in.h 1997-12-02 14:18:11.000000000 -0800 +++ linux-2.0.37-pre12/include/linux/in.h 2003-08-15 15:04:50.000000000 -0700 @@ -31,6 +31,9 @@ IPPROTO_PUP = 12, /* PUP protocol */ IPPROTO_UDP = 17, /* User Datagram Protocol */ IPPROTO_IDP = 22, /* XNS IDP protocol */ + IPPROTO_GRE = 47, /* GRE Encapsulation used by PPTP et al */ + IPPROTO_ESP = 50, /* ESP protocol for IPSec */ + IPPROTO_AH = 51, /* AH protocol for IPSec */ IPPROTO_RAW = 255, /* Raw IP packets */ IPPROTO_MAX diff -urN linux-2.0.37-pre11/include/net/ip_masq.h linux-2.0.37-pre12/include/net/ip_masq.h --- linux-2.0.37-pre11/include/net/ip_masq.h 2003-08-15 15:04:50.000000000 -0700 +++ linux-2.0.37-pre12/include/net/ip_masq.h 2003-08-15 15:04:50.000000000 -0700 @@ -85,12 +85,11 @@ unsigned flags; /* status flags */ struct ip_masq *control; /* Corresponding control connection */ #ifdef CONFIG_IP_MASQUERADE_IPSEC - struct ip_masq *d_link; /* hashed link ptr */ + struct ip_masq *d_link; /* hashed link ptr */ __u32 ospi, ispi; /* outbound and inbound SPI keys for IPSEC */ - /* also the cookie for ISAKMP masq (maybe) */ + /* also the icookie for ISAKMP masquerade */ short ocnt; /* counter of inits sent - limit blocking */ - short blocking; /* if we're blocking another host */ - + short blocking; /* if we're blocking another host */ #endif /* CONFIG_IP_MASQUERADE_IPSEC */ }; diff -urN linux-2.0.37-pre11/mm/mmap.c linux-2.0.37-pre12/mm/mmap.c --- linux-2.0.37-pre11/mm/mmap.c 2003-08-15 15:04:50.000000000 -0700 +++ linux-2.0.37-pre12/mm/mmap.c 1998-11-15 10:33:20.000000000 -0800 @@ -69,21 +69,20 @@ unsigned long newbrk, oldbrk; struct mm_struct *mm = current->mm; - down(&mm->mmap_sem); - if (brk < mm->end_code) - goto out; + return mm->brk; newbrk = PAGE_ALIGN(brk); oldbrk = PAGE_ALIGN(mm->brk); if (oldbrk == newbrk) - goto set_brk; + return mm->brk = brk; /* * Always allow shrinking brk */ if (brk <= mm->brk) { + mm->brk = brk; do_munmap(newbrk, oldbrk-newbrk); - goto set_brk; + return brk; } /* * Check against rlimit and stack.. @@ -92,19 +91,19 @@ if (rlim >= RLIM_INFINITY) rlim = ~0; if (brk - mm->end_code > rlim) - goto out; + return mm->brk; /* * Check against existing mmap mappings. */ if (find_vma_intersection(mm, oldbrk, newbrk+PAGE_SIZE)) - goto out; + return mm->brk; /* * Check if we have enough memory.. */ if (!vm_enough_memory((newbrk-oldbrk) >> PAGE_SHIFT)) - goto out; + return mm->brk; /* * Ok, looks good - let it rip. @@ -112,12 +111,8 @@ if(do_mmap(NULL, oldbrk, newbrk-oldbrk, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_FIXED|MAP_PRIVATE, 0) != oldbrk) - goto out; -set_brk: - mm->brk = brk; -out: - up(&mm->mmap_sem); - return mm->brk; + return mm->brk; + return mm->brk = brk; } /* @@ -789,12 +784,7 @@ asmlinkage int sys_munmap(unsigned long addr, size_t len) { - int ret; - - down(¤t->mm->mmap_sem); - ret = do_munmap(addr, len); - up(¤t->mm->mmap_sem); - return ret; + return do_munmap(addr, len); } /* @@ -806,7 +796,7 @@ int do_munmap(unsigned long addr, size_t len) { struct vm_area_struct *mpnt, *prev, *next, **npp, *free; - + if ((addr & ~PAGE_MASK) || addr > MAX_USER_ADDR || len > MAX_USER_ADDR-addr) return -EINVAL; @@ -864,6 +854,7 @@ } while (free); /* we could zap the page tables here too.. */ + return 0; } @@ -989,9 +980,10 @@ { struct vm_area_struct *prev, *mpnt, *next; + down(&mm->mmap_sem); mpnt = find_vma(mm, start_addr); if (!mpnt) - return; + goto no_vma; avl_neighbours(mpnt, mm->mmap_avl, &prev, &next); /* we have prev->vm_next == mpnt && mpnt->vm_next = next */ @@ -1051,4 +1043,6 @@ kfree_s(mpnt, sizeof(*mpnt)); mpnt = prev; } +no_vma: + up(&mm->mmap_sem); } diff -urN linux-2.0.37-pre11/net/ipv4/Config.in linux-2.0.37-pre12/net/ipv4/Config.in --- linux-2.0.37-pre11/net/ipv4/Config.in 2003-08-15 15:04:50.000000000 -0700 +++ linux-2.0.37-pre12/net/ipv4/Config.in 2003-08-15 15:04:50.000000000 -0700 @@ -16,21 +16,23 @@ comment 'Protocol-specific masquerading support will be built as modules.' if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then bool 'IP: ipautofw masquerading (EXPERIMENTAL)' CONFIG_IP_MASQUERADE_IPAUTOFW - bool 'IP: MS PPTP client masq support (EXPERIMENTAL)' CONFIG_IP_MASQUERADE_PPTP + bool 'IP: MS PPTP masq support (EXPERIMENTAL)' CONFIG_IP_MASQUERADE_PPTP if [ "$CONFIG_IP_MASQUERADE_PPTP" = "y" ]; then + bool 'IP: MS PPTP Call ID masq support (EXPERIMENTAL)' CONFIG_IP_MASQUERADE_PPTP_MULTICLIENT bool 'IP: MS PPTP masq debugging' DEBUG_IP_MASQUERADE_PPTP if [ "$DEBUG_IP_MASQUERADE_PPTP" = "y" ]; then bool 'IP: MS PPTP masq verbose debugging' DEBUG_IP_MASQUERADE_PPTP_VERBOSE fi - fi - bool 'IP: IPSEC ESP & ISAKMP masq support (EXPERIMENTAL)' CONFIG_IP_MASQUERADE_IPSEC - if [ "$CONFIG_IP_MASQUERADE_IPSEC" = "y" ]; then - int 'IP: IPSEC masq table lifetime (minutes)' CONFIG_IP_MASQUERADE_IPSEC_EXPIRE 30 - bool 'IP: IPSEC masq debugging' DEBUG_IP_MASQUERADE_IPSEC - if [ "$DEBUG_IP_MASQUERADE_IPSEC" = "y" ]; then - bool 'IP: IPSEC masq verbose debugging' DEBUG_IP_MASQUERADE_IPSEC_VERBOSE - fi - fi + fi + bool 'IP: IPSEC ESP & ISAKMP masq support (EXPERIMENTAL)' CONFIG_IP_MASQUERADE_IPSEC + if [ "$CONFIG_IP_MASQUERADE_IPSEC" = "y" ]; then + int 'IP: IPSEC masq table lifetime (minutes)' CONFIG_IP_MASQUERADE_IPSEC_EXPIRE 30 + bool 'IP: Disable inbound ESP destination guessing' CONFIG_IP_MASQUERADE_IPSEC_NOGUESS + bool 'IP: IPSEC masq debugging' DEBUG_IP_MASQUERADE_IPSEC + if [ "$DEBUG_IP_MASQUERADE_IPSEC" = "y" ]; then + bool 'IP: IPSEC masq verbose debugging' DEBUG_IP_MASQUERADE_IPSEC_VERBOSE + fi + fi fi bool 'IP: ICMP masquerading' CONFIG_IP_MASQUERADE_ICMP fi diff -urN linux-2.0.37-pre11/net/ipv4/ip_masq.c linux-2.0.37-pre12/net/ipv4/ip_masq.c --- linux-2.0.37-pre11/net/ipv4/ip_masq.c 2003-08-15 15:04:50.000000000 -0700 +++ linux-2.0.37-pre12/net/ipv4/ip_masq.c 2003-08-15 15:04:50.000000000 -0700 @@ -46,8 +46,6 @@ #define IP_MASQ_TAB_SIZE 256 /* must be power of 2 */ -#define IPPROTO_GRE 47 /* GRE Encapsulation used by PPTP */ - #ifdef CONFIG_IP_MASQUERADE_PPTP /* * This is clumsier than it otherwise might be (i.e. the @@ -60,6 +58,9 @@ * be somewhat more generic. * * Maybe for 2.0.38 - we'll see. + * + * John Hardin gets all blame... + * See also http://www.wolfenet.com/~jhardin/ip_masq_vpn.html */ static const char *strGREProt = "GRE"; @@ -125,9 +126,6 @@ #endif /* CONFIG_IP_MASQUERADE_PPTP */ -#define IPPROTO_ESP 50 /* ESP protocol for IPSEC */ -#define IPPROTO_AH 51 /* AH protocol for IPSEC */ - #ifdef CONFIG_IP_MASQUERADE_IPSEC /* * The above comments about PPTP apply here, too. This should all be a module. @@ -1262,8 +1260,6 @@ /* * Masquerade of GRE connections * to support a PPTP VPN client or server. - * John Hardin gets all blame... - * See also http://www.wolfenet.com/~jhardin/ip_masq_pptp.html */ /* @@ -1679,8 +1675,10 @@ pptph = (struct PptpPacketHeader *)&(((char *)iph)[sizeof(struct iphdr) + sizeof(struct tcphdr)]); #ifdef DEBUG_IP_MASQUERADE_PPTP_VERBOSE printk(KERN_DEBUG "ip_masq_pptp(): "); - printk("LEN=%d TY=%d MC=%lX\n", ntohs(pptph->packetLength), + printk("LEN=%d TY=%d MC=%lX", ntohs(pptph->packetLength), ntohs(pptph->packetType), ntohl(pptph->magicCookie)); + printk(" from %s", in_ntoa(iph->saddr)); + printk(" to %s\n", in_ntoa(iph->daddr)); #endif /* DEBUG_IP_MASQUERADE_PPTP_VERBOSE */ if (ntohs(pptph->packetType) == PPTP_CONTROL_PACKET && @@ -1735,7 +1733,7 @@ } break; case PPTP_OUT_CALL_REPLY: - if (iph->saddr == ms->daddr) /* inbound only */ + if (iph->saddr == ms->daddr) /* inbound (masqueraded client) */ { #ifdef DEBUG_IP_MASQUERADE_PPTP printk(KERN_DEBUG "ip_masq_pptp(): "); @@ -1799,7 +1797,7 @@ } break; case PPTP_IN_CALL_REPLY: - if (iph->saddr == ms->daddr) /* inbound only */ + if (iph->saddr == ms->daddr) /* inbound (masqueraded client) */ { #ifdef DEBUG_IP_MASQUERADE_PPTP printk(KERN_DEBUG "ip_masq_pptp(): "); @@ -1948,6 +1946,11 @@ * This will DoS the server for the duration of the connection * attempt, so keep the masq entry's lifetime short until a * response comes in. + * If multiple masqueraded hosts are in contention for the same + * remote host, enforce round-robin access. This may lead to + * misassociation of response traffic if the response is delayed + * a great deal, but the masqueraded hosts will clean that up + * if it happens. */ int ip_fw_masq_esp(struct sk_buff **skb_p, struct device *dev) @@ -2132,10 +2135,23 @@ struct sk_buff *skb = *skb_p; struct iphdr *iph = skb->h.iph; struct ip_masq *ms; - unsigned long flags; + unsigned long flags; __u32 i_spi; __u16 fake_sport; - +#ifndef CONFIG_IP_MASQUERADE_IPSEC_NOGUESS + #define ESP_GUESS_SZ 5 /* minimum 3, please */ + #define ESP_CAND_MIN_TM 5*60*HZ /* max 10*60*HZ? */ + unsigned hash; + int i, ii, + ncand = 0, nguess = 0; + __u16 isakmp; + __u32 cand_ip, + guess_ip[ESP_GUESS_SZ]; + unsigned long cand_tm, + guess_tm[ESP_GUESS_SZ]; + struct sk_buff *skb_cl; + struct iphdr *iph_cl; +#endif /* CONFIG_IP_MASQUERADE_IPSEC_NOGUESS */ i_spi = *((__u32 *)&(((char *)iph)[iph->ihl*4])); fake_sport = (__u16) ntohl(i_spi) & 0xffff; @@ -2150,14 +2166,15 @@ /* illegal SPI - discard */ printk(KERN_INFO "ip_fw_demasq_esp(): "); printk("zero SPI from %s discarded\n", in_ntoa(iph->saddr)); - return 0; + return -1; } if (i_spi == IPSEC_INIT_SQUELCHED) { /* Ack! This shouldn't happen! */ + /* IPSEC_INIT_SQUELCHED is chosen to be a reserved value as of 4/99 */ printk(KERN_NOTICE "ip_fw_demasq_esp(): "); printk("SPI from %s is IPSEC_INIT_SQUELCHED - modify ip_masq.c!\n", in_ntoa(iph->saddr)); - return 0; + return -1; } /* @@ -2203,6 +2220,133 @@ return 1; } +#ifndef CONFIG_IP_MASQUERADE_IPSEC_NOGUESS + /* Guess who this packet is likely intended for: + * Scan the UDP masq table for local hosts that have communicated via + * ISAKMP with the host who sent this packet. + * Using an insertion sort with duplicate IP suppression, build a list + * of the ESP_GUESS_SZ most recent ISAKMP sessions (determined by + * sorting in decreasing order of timeout timer). + * Clone the original packet and send it to those hosts, but DON'T make + * a masq table entry, as we're only guessing. It is assumed that the correct + * host will respond to the traffic and that will create a masq table entry. + * To limit the list a bit, don't consider any ISAKMP masq entries with + * less than ESP_CAND_MIN_TM time to live. This should be some value less + * than the IPSEC table timeout or *all* entries will be ignored... + */ + +#ifdef DEBUG_IP_MASQUERADE_IPSEC_VERBOSE + printk(KERN_DEBUG "ip_fw_demasq_esp(): "); + printk("guessing from %s SPI %lX\n", in_ntoa(iph->saddr), ntohl(i_spi)); +#endif /* DEBUG_IP_MASQUERADE_IPSEC_VERBOSE */ + + /* zero out the guess table */ + for (i = 0;i < ESP_GUESS_SZ; i++) { + guess_ip[i] = 0; + guess_tm[i] = 0; + } + + /* scan ISAKMP sessions with the source host */ + isakmp = htons(UDP_PORT_ISAKMP); + hash = ip_masq_hash_key(IPPROTO_UDP, iph->saddr, isakmp); + for(ms = ip_masq_d_tab[hash]; ms ; ms = ms->d_link) { + if (ms->protocol == IPPROTO_UDP && + ms->daddr == iph->saddr && + ms->sport == isakmp && + ms->dport == isakmp && + ms->mport == isakmp && + ms->ospi != 0) { + /* a candidate... */ + ncand++; + cand_ip = ms->saddr; + cand_tm = ms->timer.expires - jiffies; +#ifdef DEBUG_IP_MASQUERADE_IPSEC_VERBOSE + printk(KERN_DEBUG "ip_fw_demasq_esp(): "); + printk("cand %d: IP %s TM %ld\n", ncand, in_ntoa(cand_ip), cand_tm); +#endif /* DEBUG_IP_MASQUERADE_IPSEC_VERBOSE */ + if (cand_tm > ESP_CAND_MIN_TM) { + /* traffic is recent enough, add to list (maybe) */ + for (i = 0; i < ESP_GUESS_SZ; i++) { + if (cand_tm > guess_tm[i]) { + /* newer */ + if (guess_ip[i] != 0 && cand_ip != guess_ip[i]) { + /* newer and IP different - insert */ + if (i < (ESP_GUESS_SZ - 1)) { + /* move entries down the list, + * find first entry after this slot + * where the IP is 0 (unused) or + * IP == candidate (older traffic, same host) + * rather than simply going to the end of the list, + * for efficiency (don't shift zeros) and + * duplicate IP suppression (don't keep older entries + * having the same IP) + */ + for (ii = i + 1; ii < (ESP_GUESS_SZ - 1); ii++) { + if (guess_ip[ii] == 0 || guess_ip[ii] == cand_ip) + break; + } + for (ii-- ; ii >= i; ii--) { + guess_ip[ii+1] = guess_ip[ii]; + guess_tm[ii+1] = guess_tm[ii]; + } + } + } + guess_ip[i] = cand_ip; + guess_tm[i] = cand_tm; + break; + } + if (cand_ip == guess_ip[i]) { + /* fresher entry already there */ + break; + } + } + } + } + } + + if (guess_ip[0]) { + /* had guesses - send */ + if (guess_ip[1]) { + /* multiple guesses, send a copy to all */ + for (i = 0; guess_ip[i] != 0; i++) { + nguess++; +#ifdef DEBUG_IP_MASQUERADE_IPSEC_VERBOSE + printk(KERN_DEBUG "ip_fw_demasq_esp(): "); + printk("guess %d: IP %s TM %ld\n", nguess, in_ntoa(guess_ip[i]), guess_tm[i]); +#endif /* DEBUG_IP_MASQUERADE_IPSEC_VERBOSE */ + /* duplicate and send the skb */ + if ((skb_cl = skb_copy(skb, GFP_ATOMIC)) == NULL) { + printk(KERN_INFO "ip_fw_demasq_esp(): "); + printk("guessing: cannot copy skb\n"); + } else { + iph_cl = skb_cl->h.iph; + iph_cl->daddr = guess_ip[i]; + ip_send_check(iph_cl); + ip_forward(skb_cl, dev, IPFWD_MASQUERADED, iph_cl->daddr); + kfree_skb(skb_cl, FREE_WRITE); + } + } +#ifdef DEBUG_IP_MASQUERADE_IPSEC + printk(KERN_INFO "ip_fw_demasq_esp(): "); + printk("guessing from %s SPI %lX sent to", in_ntoa(iph->saddr), ntohl(i_spi)); + printk(" %d hosts (%d cand)\n", nguess, ncand); +#endif /* DEBUG_IP_MASQUERADE_IPSEC */ + return -1; /* discard original packet */ + } else { + /* only one guess, send original packet to that host */ + iph->daddr = guess_ip[0]; + ip_send_check(iph); + +#ifdef DEBUG_IP_MASQUERADE_IPSEC + printk(KERN_INFO "ip_fw_demasq_esp(): "); + printk("guessing from %s SPI %lX sent to", in_ntoa(iph->saddr), ntohl(i_spi)); + printk(" %s (%d cand)\n", in_ntoa(guess_ip[0]), ncand); +#endif /* DEBUG_IP_MASQUERADE_IPSEC */ + return 1; + } + } +#endif /* CONFIG_IP_MASQUERADE_IPSEC_NOGUESS */ + /* sorry, all this trouble for a no-hit :) */ printk(KERN_INFO "ip_fw_demasq_esp(): "); printk("Inbound from %s SPI %lX has no masq table entry.\n", in_ntoa(iph->saddr), ntohl(i_spi)); @@ -2240,38 +2384,14 @@ if (iph->protocol==IPPROTO_ICMP) return (ip_fw_masq_icmp(skb_ptr,dev)); - if (iph->protocol==IPPROTO_GRE) #ifdef CONFIG_IP_MASQUERADE_PPTP + if (iph->protocol==IPPROTO_GRE) return (ip_fw_masq_gre(skb_ptr,dev)); -#else - { - /* received the traffic but can't handle it - let user know. */ - printk(KERN_INFO "MASQ: %s %s ", "GRE", in_ntoa(iph->saddr)); - printk("-> %s: ", in_ntoa(iph->daddr)); - printk("%s Masq not enabled - reconfigure kernel\n", "PPTP"); - return -1; - } #endif /* CONFIG_IP_MASQUERADE_PPTP */ - if (iph->protocol==IPPROTO_ESP) #ifdef CONFIG_IP_MASQUERADE_IPSEC + if (iph->protocol==IPPROTO_ESP) return (ip_fw_masq_esp(skb_ptr,dev)); -#else - { - /* received the traffic but can't handle it - let user know. */ - printk(KERN_INFO "MASQ: %s %s ", "ESP", in_ntoa(iph->saddr)); - printk("-> %s: ", in_ntoa(iph->daddr)); - printk("%s Masq not enabled - reconfigure kernel\n", "IPSEC/ISAKMP"); - return -1; - } #endif /* CONFIG_IP_MASQUERADE_IPSEC */ - if (iph->protocol==IPPROTO_AH) - { - /* received the traffic but can't handle it - let user know. */ - printk(KERN_INFO "MASQ: %s %s ", "AH", in_ntoa(iph->saddr)); - printk("-> %s: ", in_ntoa(iph->daddr)); - printk("protocol cannot be masqueraded.\n"); - return -1; - } if (iph->protocol!=IPPROTO_UDP && iph->protocol!=IPPROTO_TCP) return -1; @@ -2421,6 +2541,13 @@ if (masq_proto_num(iph->protocol)==0) { +#ifdef CONFIG_IP_MASQUERADE_IPSEC + if (iph->protocol == IPPROTO_UDP && ntohs(portptr[0]) == UDP_PORT_ISAKMP && ntohs(portptr[1]) == UDP_PORT_ISAKMP) { + /* ISAKMP timeout should be same as ESP timeout to allow for rekeying */ + timeout = MASQUERADE_EXPIRE_IPSEC; + } else +#endif /* CONFIG_IP_MASQUERADE_IPSEC */ + timeout = ip_masq_expire->udp_timeout; recalc_check((struct udphdr *)portptr,iph->saddr,iph->daddr,size); } @@ -2935,15 +3062,15 @@ portptr = (__u16 *)&(((char *)iph)[iph->ihl*4]); if ((ntohs(portptr[1]) < PORT_MASQ_BEGIN || ntohs(portptr[1]) > PORT_MASQ_END) +#ifdef CONFIG_IP_MASQUERADE_IPSEC + && ((iph->protocol != IPPROTO_UDP) || (ntohs(portptr[0]) != UDP_PORT_ISAKMP) || (ntohs(portptr[1]) != UDP_PORT_ISAKMP)) +#endif /* CONFIG_IP_MASQUERADE_IPSEC */ #ifdef CONFIG_IP_MASQUERADE_IPAUTOFW && !ip_autofw_check_range(iph->saddr, portptr[1], iph->protocol, 0) && !ip_autofw_check_direct(portptr[1], iph->protocol) && !ip_autofw_check_port(portptr[1], iph->protocol) #endif /* CONFIG_IP_MASQUERADE_IPAUTOFW */ -#ifdef CONFIG_IP_MASQUERADE_IPSEC - && ((iph->protocol != IPPROTO_UDP) || (ntohs(portptr[0]) != UDP_PORT_ISAKMP) || (ntohs(portptr[1]) != UDP_PORT_ISAKMP)) -#endif /* CONFIG_IP_MASQUERADE_IPSEC */ ) return 0; @@ -3088,6 +3215,14 @@ if (masq_proto_num(iph->protocol)==0) { recalc_check((struct udphdr *)portptr,iph->saddr,iph->daddr,len); + +#ifdef CONFIG_IP_MASQUERADE_IPSEC + if (iph->protocol == IPPROTO_UDP && ntohs(portptr[0]) == UDP_PORT_ISAKMP && ntohs(portptr[1]) == UDP_PORT_ISAKMP) { + /* ISAKMP timeout should be same as ESP timeout to allow for rekeying */ + timeout = MASQUERADE_EXPIRE_IPSEC; + } else +#endif /* CONFIG_IP_MASQUERADE_IPSEC */ + timeout = ip_masq_expire->udp_timeout; } else