int ip_rewrite_addrs (struct sock *sk, struct sk_buff *skb, struct device *dev) { u32 new_saddr = dev->pa_addr; struct iphdr *iph; /* * Be carefull: new_saddr must be !0 */ if (!new_saddr) { printk(KERN_WARNING "ip_rewrite_addrs(): NULL device \"%s\" addr\n", dev->name); return 0; } /* * Ouch!, this should not happen. */ if (!sk->saddr || !sk->rcv_saddr) { printk(KERN_WARNING "ip_rewrite_addrs(): not valid sock addrs: saddr=%08lX rcv_saddr=%08lX", ntohl(sk->saddr), ntohl(sk->rcv_saddr)); return 0; } /* * Be verbose if sysctl value & 2 */ if (sysctl_ip_dynaddr & 2) { printk(KERN_INFO "ip_rewrite_addrs(): shifting saddr from %s", in_ntoa(skb->saddr)); printk(" to %s (state %d)\n", in_ntoa(new_saddr), sk->state); } iph = skb->ip_hdr; if (new_saddr != iph->saddr) { iph->saddr = new_saddr; skb->saddr = new_saddr; ip_send_check(iph); } else if (sysctl_ip_dynaddr & 2) { printk(KERN_WARNING "ip_rewrite_addrs(): skb already changed (???).\n"); return 0; } /* * Maybe whe are in a skb chain loop and socket address has * yet been 'damaged'. */ if (new_saddr != sk->saddr) { sk->saddr = new_saddr; sk->rcv_saddr = new_saddr; sk->prot->rehash(sk); } else if (sysctl_ip_dynaddr & 2) printk(KERN_NOTICE "ip_rewrite_addrs(): no change needed for sock\n"); return 1; }
/* 构建以太网头部的回调函数 */ int eth_header(unsigned char *buff, struct device *dev, unsigned short type, unsigned long daddr, unsigned long saddr, unsigned len) { struct ethhdr *eth; DPRINTF((DBG_DEV, "ETH: header(%s, ", in_ntoa(saddr))); DPRINTF((DBG_DEV, "%s, 0x%X)\n", in_ntoa(daddr), type)); /* Fill in the basic Ethernet MAC header. */ eth = (struct ethhdr *) buff; eth->h_proto = htons(type); /* We don't ARP for the LOOPBACK device... */ if (dev->flags & IFF_LOOPBACK) { DPRINTF((DBG_DEV, "ETH: No header for loopback\n")); memcpy(eth->h_source, dev->dev_addr, dev->addr_len); memset(eth->h_dest, 0, dev->addr_len); return(dev->hard_header_len); } /* Check if we can use the MAC BROADCAST address. */ if (chk_addr(daddr) == IS_BROADCAST) { DPRINTF((DBG_DEV, "ETH: Using MAC Broadcast\n")); memcpy(eth->h_source, dev->dev_addr, dev->addr_len); memcpy(eth->h_dest, dev->broadcast, dev->addr_len); return(dev->hard_header_len); } cli(); memcpy(eth->h_source, &saddr, 4); /* No. Ask ARP to resolve the Ethernet address. */ if (arp_find(eth->h_dest, daddr, dev, dev->pa_addr)) { sti(); if(type!=ETH_P_IP) printk("Erk: protocol %X got into an arp request state!\n",type); return(-dev->hard_header_len); } else { memcpy(eth->h_source,dev->dev_addr,dev->addr_len); /* This was missing causing chaos if the header built correctly! */ sti(); return(dev->hard_header_len); } }
/* Rebuild the Ethernet MAC header. */ int eth_rebuild_header(void *buff, struct device *dev) { struct ethhdr *eth; unsigned long src, dst; DPRINTF((DBG_DEV, "ETH: Using MAC Broadcast\n")); eth = (struct ethhdr *) buff; src = *(unsigned long *) eth->h_source; dst = *(unsigned long *) eth->h_dest; DPRINTF((DBG_DEV, "ETH: RebuildHeader: SRC=%s ", in_ntoa(src))); DPRINTF((DBG_DEV, "DST=%s\n", in_ntoa(dst))); if(eth->h_proto!=htons(ETH_P_ARP)) /* This ntohs kind of helps a bit! */ if (arp_find(eth->h_dest, dst, dev, dev->pa_addr /* src */)) return(1); memcpy(eth->h_source, dev->dev_addr, dev->addr_len); return(0); }
static void arp_send_q(struct arp_table *entry, unsigned char *hw_dest) { struct sk_buff *skb; unsigned long flags; /* * Empty the entire queue, building its data up ready to send */ if(!(entry->flags&ATF_COM)) { printk("arp_send_q: incomplete entry for %s\n", in_ntoa(entry->ip)); return; } save_flags(flags); cli(); while((skb = skb_dequeue(&entry->skb)) != NULL) { IS_SKB(skb); skb_device_lock(skb); restore_flags(flags); if(!skb->dev->rebuild_header(skb->data,skb->dev,skb->raddr,skb)) { skb->arp = 1; if(skb->sk==NULL) dev_queue_xmit(skb, skb->dev, 0); else dev_queue_xmit(skb,skb->dev,skb->sk->priority); } else { /* This routine is only ever called when 'entry' is complete. Thus this can't fail. */ printk("arp_send_q: The impossible occurred. Please notify Alan.\n"); printk("arp_send_q: active entity %s\n",in_ntoa(entry->ip)); printk("arp_send_q: failed to find %s\n",in_ntoa(skb->raddr)); } } restore_flags(flags); }
/* * Obtain an NFS file handle for the given host and path */ int nfs_mount(struct sockaddr_in *addr, char *path, struct nfs_fh *fh) { struct rpc_clnt *mnt_clnt; struct mnt_fhstatus result = { 0, fh }; char hostname[32]; int status; dprintk("NFS: nfs_mount(%08x:%s)\n", (unsigned)ntohl(addr->sin_addr.s_addr), path); strcpy(hostname, in_ntoa(addr->sin_addr.s_addr)); if (!(mnt_clnt = mnt_create(hostname, addr))) return -EACCES; status = rpc_call(mnt_clnt, NFS_MNTPROC_MNT, path, &result, 0); return status < 0? status : (result.status? -EACCES : 0); }
int ip_fw_masq_icmp(struct sk_buff **skb_p, struct device *dev) { struct sk_buff *skb = *skb_p; struct iphdr *iph = skb->h.iph; struct icmphdr *icmph = (struct icmphdr *)((char *)iph + (iph->ihl<<2)); struct iphdr *ciph; /* The ip header contained within the ICMP */ __u16 *pptr; /* port numbers from TCP/UDP contained header */ struct ip_masq *ms; unsigned short len = ntohs(iph->tot_len) - (iph->ihl * 4); #ifdef DEBUG_CONFIG_IP_MASQUERADE_ICMP printk("Incoming forward ICMP (%d,%d) %lX -> %lX\n", icmph->type, ntohs(icmp_id(icmph)), ntohl(iph->saddr), ntohl(iph->daddr)); #endif #ifdef CONFIG_IP_MASQUERADE_ICMP if ((icmph->type == ICMP_ECHO ) || (icmph->type == ICMP_TIMESTAMP ) || (icmph->type == ICMP_INFO_REQUEST ) || (icmph->type == ICMP_ADDRESS )) { #ifdef DEBUG_CONFIG_IP_MASQUERADE_ICMP printk("MASQ: icmp request rcv %lX->%lX id %d type %d\n", ntohl(iph->saddr), ntohl(iph->daddr), ntohs(icmp_id(icmph)), icmph->type); #endif ms = ip_masq_out_get_2(iph->protocol, iph->saddr, icmp_id(icmph), iph->daddr, icmp_hv_req(icmph)); if (ms == NULL) { ms = ip_masq_new(dev, iph->protocol, iph->saddr, icmp_id(icmph), iph->daddr, icmp_hv_req(icmph), 0); if (ms == NULL) return (-1); #ifdef DEBUG_CONFIG_IP_MASQUERADE_ICMP printk("MASQ: Create new icmp entry\n"); #endif } ip_masq_set_expire(ms, 0); /* Rewrite source address */ /* * If sysctl !=0 and no pkt has been received yet * in this tunnel and routing iface address has changed... * "You are welcome, diald". */ if ( sysctl_ip_dynaddr && ms->flags & IP_MASQ_F_NO_REPLY && dev->pa_addr != ms->maddr) { unsigned long flags; #ifdef DEBUG_CONFIG_IP_MASQUERADE printk(KERN_INFO "ip_fw_masq_icmp(): change masq.addr %s", in_ntoa(ms->maddr)); printk("-> %s\n", in_ntoa(dev->pa_addr)); #endif save_flags(flags); cli(); ip_masq_unhash(ms); ms->maddr = dev->pa_addr; ip_masq_hash(ms); restore_flags(flags); } iph->saddr = ms->maddr; ip_send_check(iph); /* Rewrite port (id) */ (icmph->un).echo.id = ms->mport; icmph->checksum = 0; icmph->checksum = ip_compute_csum((unsigned char *)icmph, len); ip_masq_set_expire(ms, MASQUERADE_EXPIRE_ICMP); #ifdef DEBUG_CONFIG_IP_MASQUERADE_ICMP printk("MASQ: icmp request rwt %lX->%lX id %d type %d\n", ntohl(iph->saddr), ntohl(iph->daddr), ntohs(icmp_id(icmph)), icmph->type); #endif return (1); } #endif /* * Work through seeing if this is for us. * These checks are supposed to be in an order that * means easy things are checked first to speed up * processing.... however this means that some * packets will manage to get a long way down this * stack and then be rejected, but thats life */ if ((icmph->type != ICMP_DEST_UNREACH) && (icmph->type != ICMP_SOURCE_QUENCH) && (icmph->type != ICMP_TIME_EXCEEDED)) return 0; /* Now find the contained IP header */ ciph = (struct iphdr *) (icmph + 1); #ifdef CONFIG_IP_MASQUERADE_ICMP if (ciph->protocol == IPPROTO_ICMP) { /* * This section handles ICMP errors for ICMP packets */ struct icmphdr *cicmph = (struct icmphdr *)((char *)ciph + (ciph->ihl<<2)); #ifdef DEBUG_CONFIG_IP_MASQUERADE_ICMP printk("MASQ: fw icmp/icmp rcv %lX->%lX id %d type %d\n", ntohl(ciph->saddr), ntohl(ciph->daddr), ntohs(icmp_id(cicmph)), cicmph->type); #endif ms = ip_masq_out_get_2(ciph->protocol, ciph->daddr, icmp_id(cicmph), ciph->saddr, icmp_hv_rep(cicmph)); if (ms == NULL) return 0; /* Now we do real damage to this packet...! */ /* First change the source IP address, and recalc checksum */ iph->saddr = ms->maddr; ip_send_check(iph); /* Now change the *dest* address in the contained IP */ ciph->daddr = ms->maddr; ip_send_check(ciph); /* Change the ID to the masqed one! */ (cicmph->un).echo.id = ms->mport; /* And finally the ICMP checksum */ icmph->checksum = 0; icmph->checksum = ip_compute_csum((unsigned char *) icmph, len); #ifdef DEBUG_CONFIG_IP_MASQUERADE_ICMP printk("MASQ: fw icmp/icmp rwt %lX->%lX id %d type %d\n", ntohl(ciph->saddr), ntohl(ciph->daddr), ntohs(icmp_id(cicmph)), cicmph->type); #endif return 1; } #endif /* CONFIG_IP_MASQUERADE_ICMP */ /* We are only interested ICMPs generated from TCP or UDP packets */ if ((ciph->protocol != IPPROTO_UDP) && (ciph->protocol != IPPROTO_TCP)) return 0; /* * Find the ports involved - this packet was * incoming so the ports are right way round * (but reversed relative to outer IP header!) */ pptr = (__u16 *)&(((char *)ciph)[ciph->ihl*4]); /* Ensure the checksum is correct */ if (ip_compute_csum((unsigned char *) icmph, len)) { /* Failed checksum! */ printk(KERN_DEBUG "MASQ: forward ICMP: failed checksum from %s!\n", in_ntoa(iph->saddr)); return(-1); } #ifdef DEBUG_CONFIG_IP_MASQUERADE printk("Handling forward ICMP for %lX:%X -> %lX:%X\n", ntohl(ciph->saddr), ntohs(pptr[0]), ntohl(ciph->daddr), ntohs(pptr[1])); #endif /* This is pretty much what ip_masq_out_get() does */ ms = ip_masq_out_get_2(ciph->protocol, ciph->daddr, pptr[1], ciph->saddr, pptr[0]); if (ms == NULL) return 0; /* Now we do real damage to this packet...! */ /* First change the source IP address, and recalc checksum */ iph->saddr = ms->maddr; ip_send_check(iph); /* Now change the *dest* address in the contained IP */ ciph->daddr = ms->maddr; ip_send_check(ciph); /* the TCP/UDP dest port - cannot redo check */ pptr[1] = ms->mport; /* And finally the ICMP checksum */ icmph->checksum = 0; icmph->checksum = ip_compute_csum((unsigned char *) icmph, len); #ifdef DEBUG_CONFIG_IP_MASQUERADE printk("Rewrote forward ICMP to %lX:%X -> %lX:%X\n", ntohl(ciph->saddr), ntohs(pptr[0]), ntohl(ciph->daddr), ntohs(pptr[1])); #endif return 1; }
int ip_fw_masquerade(struct sk_buff **skb_ptr, struct device *dev) { struct sk_buff *skb=*skb_ptr; struct iphdr *iph = skb->h.iph; __u16 *portptr; struct ip_masq *ms; int size; unsigned long timeout; /* * We can only masquerade protocols with ports... * [TODO] * We may need to consider masq-ing some ICMP related to masq-ed protocols */ if (iph->protocol==IPPROTO_ICMP) return (ip_fw_masq_icmp(skb_ptr,dev)); if (iph->protocol!=IPPROTO_UDP && iph->protocol!=IPPROTO_TCP) return -1; /* * Now hunt the list to see if we have an old entry */ portptr = (__u16 *)&(((char *)iph)[iph->ihl*4]); #ifdef DEBUG_CONFIG_IP_MASQUERADE printk("Outgoing %s %lX:%X -> %lX:%X\n", masq_proto_name(iph->protocol), ntohl(iph->saddr), ntohs(portptr[0]), ntohl(iph->daddr), ntohs(portptr[1])); #endif ms = ip_masq_out_get(iph); if (ms!=NULL) { ip_masq_set_expire(ms,0); /* * If sysctl !=0 and no pkt has been received yet * in this tunnel and routing iface address has changed... * "You are welcome, diald". */ if ( sysctl_ip_dynaddr && ms->flags & IP_MASQ_F_NO_REPLY && dev->pa_addr != ms->maddr) { unsigned long flags; if (sysctl_ip_dynaddr > 1) { printk(KERN_INFO "ip_fw_masquerade(): change maddr from %s", in_ntoa(ms->maddr)); printk(" to %s\n", in_ntoa(dev->pa_addr)); } save_flags(flags); cli(); ip_masq_unhash(ms); ms->maddr = dev->pa_addr; ip_masq_hash(ms); restore_flags(flags); } /* * Set sport if not defined yet (e.g. ftp PASV). Because * masq entries are hashed on sport, unhash with old value * and hash with new. */ if ( ms->flags & IP_MASQ_F_NO_SPORT && ms->protocol == IPPROTO_TCP ) { unsigned long flags; ms->flags &= ~IP_MASQ_F_NO_SPORT; save_flags(flags); cli(); ip_masq_unhash(ms); ms->sport = portptr[0]; ip_masq_hash(ms); /* hash on new sport */ restore_flags(flags); #ifdef DEBUG_CONFIG_IP_MASQUERADE printk("ip_fw_masquerade(): filled sport=%d\n", ntohs(ms->sport)); #endif } } #ifdef CONFIG_IP_MASQUERADE_IPAUTOFW /* update any ipautofw entries .. */ ip_autofw_update_out(iph->saddr, iph->daddr, portptr[1], iph->protocol); #endif /* CONFIG_IP_MASQUERADE_IPAUTOFW */ /* * Nope, not found, create a new entry for it */ if (ms==NULL) { #ifdef CONFIG_IP_MASQUERADE_IPAUTOFW /* if the source port is supposed to match the masq port, then make it so */ if (ip_autofw_check_direct(portptr[1],iph->protocol)) ms = ip_masq_new_enh(dev, iph->protocol, iph->saddr, portptr[0], iph->daddr, portptr[1], 0, portptr[0]); else #endif /* CONFIG_IP_MASQUERADE_IPAUTOFW */ ms = ip_masq_new_enh(dev, iph->protocol, iph->saddr, portptr[0], iph->daddr, portptr[1], 0, 0); if (ms == NULL) return -1; } /* * Change the fragments origin */ size = skb->len - ((unsigned char *)portptr - skb->h.raw); /* * Set iph addr and port from ip_masq obj. */ iph->saddr = ms->maddr; portptr[0] = ms->mport; /* * Attempt ip_masq_app call. * will fix ip_masq and iph seq stuff */ if (ip_masq_app_pkt_out(ms, skb_ptr, dev) != 0) { /* * skb has possibly changed, update pointers. */ skb = *skb_ptr; iph = skb->h.iph; portptr = (__u16 *)&(((char *)iph)[iph->ihl*4]); size = skb->len - ((unsigned char *)portptr-skb->h.raw); } /* * Adjust packet accordingly to protocol */ if (masq_proto_num(iph->protocol)==0) { timeout = ip_masq_expire->udp_timeout; recalc_check((struct udphdr *)portptr,iph->saddr,iph->daddr,size); } else { struct tcphdr *th; th = (struct tcphdr *)portptr; /* Set the flags up correctly... */ if (th->fin) { ms->flags |= IP_MASQ_F_SAW_FIN_OUT; } if (th->rst) { ms->flags |= IP_MASQ_F_SAW_RST; } /* * Timeout depends if FIN packet has been seen * Very short timeout if RST packet seen. */ if (ms->flags & IP_MASQ_F_SAW_RST) { timeout = 1; } else if ((ms->flags & IP_MASQ_F_SAW_FIN) == IP_MASQ_F_SAW_FIN) { timeout = ip_masq_expire->tcp_fin_timeout; } else timeout = ip_masq_expire->tcp_timeout; skb->csum = csum_partial((void *)(th + 1), size - sizeof(*th), 0); tcp_send_check(th,iph->saddr,iph->daddr,size,skb); } ip_masq_set_expire(ms, timeout); ip_send_check(iph); #ifdef DEBUG_CONFIG_IP_MASQUERADE printk("O-routed from %lX:%X over %s\n",ntohl(ms->maddr),ntohs(ms->mport),dev->name); #endif return 0; }
int ip_fw_demasquerade(struct sk_buff **skb_p, struct device *dev) { struct sk_buff *skb = *skb_p; struct iphdr *iph = skb->h.iph; __u16 *portptr; struct ip_masq *ms; unsigned short len; unsigned long timeout; #ifdef CONFIG_IP_MASQUERADE_IPAUTOFW struct ip_autofw *af; #endif /* CONFIG_IP_MASQUERADE_IPAUTOFW */ switch (iph->protocol) { case IPPROTO_ICMP: return(ip_fw_demasq_icmp(skb_p, dev)); case IPPROTO_TCP: case IPPROTO_UDP: /* Make sure packet is in the masq range */ portptr = (__u16 *)&(((char *)iph)[iph->ihl*4]); if ((ntohs(portptr[1]) < PORT_MASQ_BEGIN || ntohs(portptr[1]) > PORT_MASQ_END) #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 */ ) return 0; /* Check that the checksum is OK */ len = ntohs(iph->tot_len) - (iph->ihl * 4); if ((iph->protocol == IPPROTO_UDP) && (portptr[3] == 0)) /* No UDP checksum */ break; switch (skb->ip_summed) { case CHECKSUM_NONE: skb->csum = csum_partial((char *)portptr, len, 0); case CHECKSUM_HW: if (csum_tcpudp_magic(iph->saddr, iph->daddr, len, iph->protocol, skb->csum)) { printk(KERN_DEBUG "MASQ: failed TCP/UDP checksum from %s!\n", in_ntoa(iph->saddr)); return -1; } default: /* CHECKSUM_UNNECESSARY */ } break; default: return 0; } #ifdef DEBUG_CONFIG_IP_MASQUERADE printk("Incoming %s %lX:%X -> %lX:%X\n", masq_proto_name(iph->protocol), ntohl(iph->saddr), ntohs(portptr[0]), ntohl(iph->daddr), ntohs(portptr[1])); #endif /* * reroute to original host:port if found... */ ms = ip_masq_in_get(iph); #ifdef CONFIG_IP_MASQUERADE_IPAUTOFW if (ms == NULL && (af=ip_autofw_check_range(iph->saddr, portptr[1], iph->protocol, 0))) { #ifdef DEBUG_CONFIG_IP_MASQUERADE printk("ip_autofw_check_range\n"); #endif ms = ip_masq_new_enh(dev, iph->protocol, af->where, portptr[1], iph->saddr, portptr[0], 0, portptr[1]); } if ( ms == NULL && (af=ip_autofw_check_port(portptr[1], iph->protocol)) ) { #ifdef DEBUG_CONFIG_IP_MASQUERADE printk("ip_autofw_check_port\n"); #endif ms = ip_masq_new_enh(dev, iph->protocol, af->where, htons(af->hidden), iph->saddr, portptr[0], IP_MASQ_F_AFW_PORT, htons(af->visible)); } #endif /* CONFIG_IP_MASQUERADE_IPAUTOFW */ if (ms != NULL) { #ifdef CONFIG_IP_MASQUERADE_IPAUTOFW ip_autofw_update_in(iph->saddr, portptr[1], iph->protocol); #endif /* CONFIG_IP_MASQUERADE_IPAUTOFW */ /* Stop the timer ticking.... */ ip_masq_set_expire(ms,0); /* * got reply, so clear flag */ ms->flags &= ~IP_MASQ_F_NO_REPLY; /* * Set dport if not defined yet. */ if ( ms->flags & IP_MASQ_F_NO_DPORT && ms->protocol == IPPROTO_TCP ) { ms->flags &= ~IP_MASQ_F_NO_DPORT; ms->dport = portptr[0]; #ifdef DEBUG_CONFIG_IP_MASQUERADE printk("ip_fw_demasquerade(): filled dport=%d\n", ntohs(ms->dport)); #endif } if (ms->flags & IP_MASQ_F_NO_DADDR && ms->protocol == IPPROTO_TCP) { ms->flags &= ~IP_MASQ_F_NO_DADDR; ms->daddr = iph->saddr; #ifdef DEBUG_CONFIG_IP_MASQUERADE printk("ip_fw_demasquerade(): filled daddr=%X\n", ntohs(ms->daddr)); #endif } iph->daddr = ms->saddr; portptr[1] = ms->sport; /* * Attempt ip_masq_app call. * will fix ip_masq and iph ack_seq stuff */ if (ip_masq_app_pkt_in(ms, skb_p, dev) != 0) { /* * skb has changed, update pointers. */ skb = *skb_p; iph = skb->h.iph; portptr = (__u16 *)&(((char *)iph)[iph->ihl*4]); len = ntohs(iph->tot_len) - (iph->ihl * 4); } /* * Yug! adjust UDP/TCP and IP checksums, also update * timeouts. * If a TCP RST is seen collapse the tunnel (by using short timeout)! */ if (masq_proto_num(iph->protocol)==0) { recalc_check((struct udphdr *)portptr,iph->saddr,iph->daddr,len); timeout = ip_masq_expire->udp_timeout; } else { struct tcphdr *th; skb->csum = csum_partial((void *)(((struct tcphdr *)portptr) + 1), len - sizeof(struct tcphdr), 0); tcp_send_check((struct tcphdr *)portptr,iph->saddr,iph->daddr,len,skb); /* Check if TCP FIN or RST */ th = (struct tcphdr *)portptr; if (th->fin) { ms->flags |= IP_MASQ_F_SAW_FIN_IN; } if (th->rst) { ms->flags |= IP_MASQ_F_SAW_RST; } /* Now set the timeouts */ if (ms->flags & IP_MASQ_F_SAW_RST) { timeout = 1; } else if ((ms->flags & IP_MASQ_F_SAW_FIN) == IP_MASQ_F_SAW_FIN) { timeout = ip_masq_expire->tcp_fin_timeout; } else timeout = ip_masq_expire->tcp_timeout; } ip_masq_set_expire(ms, timeout); ip_send_check(iph); #ifdef DEBUG_CONFIG_IP_MASQUERADE printk("I-routed to %lX:%X\n",ntohl(iph->daddr),ntohs(portptr[1])); #endif return 1; } /* sorry, all this trouble for a no-hit :) */ return 0; } /* * /proc/net entries */ #ifdef CONFIG_IP_MASQUERADE_IPAUTOFW static int ip_autofw_procinfo(char *buffer, char **start, off_t offset, int length, int unused) { off_t pos=0, begin=0; struct ip_autofw * af; int len=0; len=sprintf(buffer,"Type Prot Low High Vis Hid Where Last CPto CPrt Timer Flags\n"); for(af = ip_autofw_hosts; af ; af = af->next) { len+=sprintf(buffer+len,"%4X %4X %04X-%04X/%04X %04X %08lX %08lX %04X %04X %6lu %4X\n", af->type, af->protocol, af->low, af->high, af->visible, af->hidden, ntohl(af->where), ntohl(af->lastcontact), af->ctlproto, af->ctlport, (af->timer.expires<jiffies ? 0 : af->timer.expires-jiffies), af->flags); pos=begin+len; if(pos<offset) { len=0; begin=pos; } if(pos>offset+length) break; } *start=buffer+(offset-begin); len-=(offset-begin); if(len>length) len=length; return len; }
int ip_fw_demasq_icmp(struct sk_buff **skb_p, struct device *dev) { struct sk_buff *skb = *skb_p; struct iphdr *iph = skb->h.iph; struct icmphdr *icmph = (struct icmphdr *)((char *)iph + (iph->ihl<<2)); struct iphdr *ciph; /* The ip header contained within the ICMP */ __u16 *pptr; /* port numbers from TCP/UDP contained header */ struct ip_masq *ms; unsigned short len = ntohs(iph->tot_len) - (iph->ihl * 4); #ifdef DEBUG_CONFIG_IP_MASQUERADE_ICMP printk("MASQ: icmp in/rev (%d,%d) %lX -> %lX\n", icmph->type, ntohs(icmp_id(icmph)), ntohl(iph->saddr), ntohl(iph->daddr)); #endif #ifdef CONFIG_IP_MASQUERADE_ICMP if ((icmph->type == ICMP_ECHOREPLY) || (icmph->type == ICMP_TIMESTAMPREPLY) || (icmph->type == ICMP_INFO_REPLY) || (icmph->type == ICMP_ADDRESSREPLY)) { #ifdef DEBUG_CONFIG_IP_MASQUERADE_ICMP printk("MASQ: icmp reply rcv %lX->%lX id %d type %d, req %d\n", ntohl(iph->saddr), ntohl(iph->daddr), ntohs(icmp_id(icmph)), icmph->type, icmp_type_request(icmph->type)); #endif ms = ip_masq_in_get_2(iph->protocol, iph->saddr, icmp_hv_rep(icmph), iph->daddr, icmp_id(icmph)); if (ms == NULL) return 0; ip_masq_set_expire(ms,0); /* * got reply, so clear flag */ ms->flags &= ~IP_MASQ_F_NO_REPLY; /* Reset source address */ iph->daddr = ms->saddr; /* Redo IP header checksum */ ip_send_check(iph); /* Set ID to fake port number */ (icmph->un).echo.id = ms->sport; /* Reset ICMP checksum and set expiry */ icmph->checksum=0; icmph->checksum=ip_compute_csum((unsigned char *)icmph,len); ip_masq_set_expire(ms, MASQUERADE_EXPIRE_ICMP); #ifdef DEBUG_CONFIG_IP_MASQUERADE_ICMP printk("MASQ: icmp reply rwt %lX->%lX id %d type %d\n", ntohl(iph->saddr), ntohl(iph->daddr), ntohs(icmp_id(icmph)), icmph->type); #endif return 1; } else { #endif if ((icmph->type != ICMP_DEST_UNREACH) && (icmph->type != ICMP_SOURCE_QUENCH) && (icmph->type != ICMP_TIME_EXCEEDED)) return 0; #ifdef CONFIG_IP_MASQUERADE_ICMP } #endif /* * If we get here we have an ICMP error of one of the above 3 types * Now find the contained IP header */ ciph = (struct iphdr *) (icmph + 1); #ifdef CONFIG_IP_MASQUERADE_ICMP if (ciph->protocol == IPPROTO_ICMP) { /* * This section handles ICMP errors for ICMP packets * * First get a new ICMP header structure out of the IP packet */ struct icmphdr *cicmph = (struct icmphdr *)((char *)ciph + (ciph->ihl<<2)); #ifdef DEBUG_CONFIG_IP_MASQUERADE_ICMP printk("MASQ: rv icmp/icmp rcv %lX->%lX id %d type %d\n", ntohl(ciph->saddr), ntohl(ciph->daddr), ntohs(icmp_id(cicmph)), cicmph->type); #endif ms = ip_masq_in_get_2(ciph->protocol, ciph->daddr, icmp_hv_req(cicmph), ciph->saddr, icmp_id(cicmph)); if (ms == NULL) return 0; /* Now we do real damage to this packet...! */ /* First change the dest IP address, and recalc checksum */ iph->daddr = ms->saddr; ip_send_check(iph); /* Now change the *source* address in the contained IP */ ciph->saddr = ms->saddr; ip_send_check(ciph); /* Change the ID to the original one! */ (cicmph->un).echo.id = ms->sport; /* And finally the ICMP checksum */ icmph->checksum = 0; icmph->checksum = ip_compute_csum((unsigned char *) icmph, len); #ifdef DEBUG_CONFIG_IP_MASQUERADE_ICMP printk("MASQ: rv icmp/icmp rwt %lX->%lX id %d type %d\n", ntohl(ciph->saddr), ntohl(ciph->daddr), ntohs(icmp_id(cicmph)), cicmph->type); #endif return 1; } #endif /* CONFIG_IP_MASQUERADE_ICMP */ /* We are only interested ICMPs generated from TCP or UDP packets */ if ((ciph->protocol != IPPROTO_UDP) && (ciph->protocol != IPPROTO_TCP)) return 0; /* * Find the ports involved - remember this packet was * *outgoing* so the ports are reversed (and addresses) */ pptr = (__u16 *)&(((char *)ciph)[ciph->ihl*4]); if (ntohs(pptr[0]) < PORT_MASQ_BEGIN || ntohs(pptr[0]) > PORT_MASQ_END) return 0; /* Ensure the checksum is correct */ if (ip_compute_csum((unsigned char *) icmph, len)) { /* Failed checksum! */ printk(KERN_DEBUG "MASQ: reverse ICMP: failed checksum from %s!\n", in_ntoa(iph->saddr)); return(-1); } #ifdef DEBUG_CONFIG_IP_MASQUERADE printk("Handling reverse ICMP for %lX:%X -> %lX:%X\n", ntohl(ciph->saddr), ntohs(pptr[0]), ntohl(ciph->daddr), ntohs(pptr[1])); #endif /* This is pretty much what ip_masq_in_get() does, except params are wrong way round */ ms = ip_masq_in_get_2(ciph->protocol, ciph->daddr, pptr[1], ciph->saddr, pptr[0]); if (ms == NULL) return 0; /* Now we do real damage to this packet...! */ /* First change the dest IP address, and recalc checksum */ iph->daddr = ms->saddr; ip_send_check(iph); /* Now change the *source* address in the contained IP */ ciph->saddr = ms->saddr; ip_send_check(ciph); /* the TCP/UDP source port - cannot redo check */ pptr[0] = ms->sport; /* And finally the ICMP checksum */ icmph->checksum = 0; icmph->checksum = ip_compute_csum((unsigned char *) icmph, len); #ifdef DEBUG_CONFIG_IP_MASQUERADE printk("Rewrote reverse ICMP to %lX:%X -> %lX:%X\n", ntohl(ciph->saddr), ntohs(pptr[0]), ntohl(ciph->daddr), ntohs(pptr[1])); #endif return 1; }
static void icmp_unreach(struct icmphdr *icmph, struct sk_buff *skb, int len) { struct iphdr *iph; int hash; struct inet_protocol *ipprot; unsigned char *dp; struct sock *raw_sk; /* * Incomplete header ? * Only checks for the IP header, there should be an * additional check for longer headers in upper levels. */ if(len<sizeof(struct iphdr)) { icmp_statistics.IcmpInErrors++; return; } iph = (struct iphdr *) (icmph + 1); dp = (unsigned char*)iph; if(icmph->type==ICMP_TIME_EXCEEDED) { /* ABD */ play_that_funky_music (icmph); } if(icmph->type==ICMP_DEST_UNREACH) { switch(icmph->code & 15) { case ICMP_NET_UNREACH: break; case ICMP_HOST_UNREACH: break; case ICMP_PORT_UNREACH: play_that_funky_music (icmph); /* ABD */ break; case ICMP_PROT_UNREACH: break; case ICMP_FRAG_NEEDED: if (ipv4_config.no_pmtu_disc) { if (sysctl_ip_always_defrag == 0 && net_ratelimit()) printk(KERN_INFO "ICMP: %s: fragmentation needed and DF set.\n", in_ntoa(iph->daddr)); } else { unsigned short new_mtu; new_mtu = ip_rt_frag_needed(iph, ntohs(icmph->un.frag.mtu)); if (!new_mtu) return; icmph->un.frag.mtu = htons(new_mtu); } break; case ICMP_SR_FAILED: if (sysctl_ip_always_defrag == 0 && net_ratelimit()) printk(KERN_INFO "ICMP: %s: Source Route Failed.\n", in_ntoa(iph->daddr)); break; default: break; } if (icmph->code>NR_ICMP_UNREACH) return; } /* * Throw it at our lower layers * * RFC 1122: 3.2.2 MUST extract the protocol ID from the passed header. * RFC 1122: 3.2.2.1 MUST pass ICMP unreach messages to the transport layer. * RFC 1122: 3.2.2.2 MUST pass ICMP time expired messages to transport layer. */ /* * Check the other end isnt violating RFC 1122. Some routers send * bogus responses to broadcast frames. If you see this message * first check your netmask matches at both ends, if it does then * get the other vendor to fix their kit. */ if (!sysctl_icmp_ignore_bogus_error_responses) { if (inet_addr_type(iph->daddr) == RTN_BROADCAST) { if (sysctl_ip_always_defrag == 0 && net_ratelimit()) printk(KERN_WARNING "%s sent an invalid ICMP error to a broadcast.\n", in_ntoa(skb->nh.iph->saddr)); return; } } /* * Deliver ICMP message to raw sockets. Pretty useless feature? */ /* Note: See raw.c and net/raw.h, RAWV4_HTABLE_SIZE==MAX_INET_PROTOS */ hash = iph->protocol & (MAX_INET_PROTOS - 1); if ((raw_sk = raw_v4_htable[hash]) != NULL) { while ((raw_sk = raw_v4_lookup(raw_sk, iph->protocol, iph->saddr, iph->daddr, skb->dev->ifindex)) != NULL) { raw_err(raw_sk, skb); raw_sk = raw_sk->next; } } /* * This can't change while we are doing it. */ ipprot = (struct inet_protocol *) inet_protos[hash]; while(ipprot != NULL) { struct inet_protocol *nextip; nextip = (struct inet_protocol *) ipprot->next; /* * Pass it off to everyone who wants it. */ /* RFC1122: OK. Passes appropriate ICMP errors to the */ /* appropriate protocol layer (MUST), as per 3.2.2. */ if (iph->protocol == ipprot->protocol && ipprot->err_handler) ipprot->err_handler(skb, dp, len); ipprot = nextip; } }
static void icmp_redirect(struct icmphdr *icmph, struct sk_buff *skb, struct device *dev, __u32 source, __u32 daddr, int len) { struct iphdr *iph; unsigned long ip; /* * Get the copied header of the packet that caused the redirect */ if(len<=sizeof(struct iphdr)) goto flush_it; iph = (struct iphdr *) (icmph + 1); ip = iph->daddr; /* * If we are a router and we run a routing protocol, we MUST NOT follow redirects. * When using no routing protocol, we MAY follow redirects. (RFC 1812, 5.2.7.2) */ #if !defined(CONFIG_IP_DUMB_ROUTER) if (sysctl_ip_forward) { NETDEBUG(printk(KERN_INFO "icmp: ICMP redirect ignored. dest = %lX, " "orig gw = %lX, \"new\" gw = %lX, device = %s.\n", ntohl(ip), ntohl(source), ntohl(icmph->un.gateway), dev->name)); goto flush_it; } #endif switch(icmph->code & 7) { case ICMP_REDIR_NET: /* * This causes a problem with subnetted networks. What we should do * is use ICMP_ADDRESS to get the subnet mask of the problem route * and set both. But we don't.. [RFC1812 says routers MUST NOT * generate Network Redirects] */ #ifdef not_a_good_idea ip_rt_add((RTF_DYNAMIC | RTF_MODIFIED | RTF_GATEWAY), ip, 0, icmph->un.gateway, dev,0, 0, 0); #endif /* * As per RFC recommendations now handle it as * a host redirect. */ case ICMP_REDIR_HOST: /* * Add better route to host. * But first check that the redirect * comes from the old gateway.. * And make sure it's an ok host address * (not some confused thing sending our * address) */ NETDEBUG(printk(KERN_INFO "ICMP redirect from %s\n", in_ntoa(source))); ip_rt_redirect(source, ip, icmph->un.gateway, dev); break; case ICMP_REDIR_NETTOS: case ICMP_REDIR_HOSTTOS: NETDEBUG(printk(KERN_INFO "ICMP: cannot handle TOS redirects yet!\n")); break; default: break; } /* * Discard the original packet */ flush_it: kfree_skb(skb, FREE_READ); }
struct sk_buff *ip_defrag(struct iphdr *iph, struct sk_buff *skb, struct device *dev) { struct ipfrag *prev, *next, *tmp; struct ipfrag *tfp; struct ipq *qp; struct sk_buff *skb2; unsigned char *ptr; int flags, offset; int i, ihl, end; ip_statistics.IpReasmReqds++; /* * Start by cleaning up the memory */ if(ip_frag_mem>IPFRAG_HIGH_THRESH) ip_evictor(); /* * Find the entry of this IP datagram in the "incomplete datagrams" queue. */ qp = ip_find(iph); /* Is this a non-fragmented datagram? */ offset = ntohs(iph->frag_off); flags = offset & ~IP_OFFSET; offset &= IP_OFFSET; if (((flags & IP_MF) == 0) && (offset == 0)) { if (qp != NULL) ip_free(qp); /* Fragmented frame replaced by full unfragmented copy */ return(skb); } offset <<= 3; /* offset is in 8-byte chunks */ ihl = iph->ihl * 4; /* * If the queue already existed, keep restarting its timer as long * as we still are receiving fragments. Otherwise, create a fresh * queue entry. */ if (qp != NULL) { /* ANK. If the first fragment is received, * we should remember the correct IP header (with options) */ if (offset == 0) { qp->ihlen = ihl; memcpy(qp->iph, iph, ihl+8); } del_timer(&qp->timer); qp->timer.expires = jiffies + IP_FRAG_TIME; /* about 30 seconds */ qp->timer.data = (unsigned long) qp; /* pointer to queue */ qp->timer.function = ip_expire; /* expire function */ add_timer(&qp->timer); } else { /* * If we failed to create it, then discard the frame */ if ((qp = ip_create(skb, iph, dev)) == NULL) { skb->sk = NULL; kfree_skb(skb, FREE_READ); ip_statistics.IpReasmFails++; return NULL; } } /* * Attempt to construct an oversize packet. */ if(ntohs(iph->tot_len)+(int)offset>65535) { skb->sk = NULL; NETDEBUG(printk("Oversized packet received from %s\n",in_ntoa(iph->saddr))); kfree_skb(skb, FREE_READ); ip_statistics.IpReasmFails++; return NULL; } /* * Determine the position of this fragment. */ end = offset + ntohs(iph->tot_len) - ihl; /* * Point into the IP datagram 'data' part. */ ptr = skb->data + ihl; /* * Is this the final fragment? */ if ((flags & IP_MF) == 0) qp->len = end; /* * Find out which fragments are in front and at the back of us * in the chain of fragments so far. We must know where to put * this fragment, right? */ prev = NULL; for(next = qp->fragments; next != NULL; next = next->next) { if (next->offset >= offset) break; /* bingo! */ prev = next; } /* * We found where to put this one. * Check for overlap with preceding fragment, and, if needed, * align things so that any overlaps are eliminated. */ if (prev != NULL && offset < prev->end) { i = prev->end - offset; offset += i; /* ptr into datagram */ ptr += i; /* ptr into fragment data */ } /* * Look for overlap with succeeding segments. * If we can merge fragments, do it. */ for(tmp=next; tmp != NULL; tmp = tfp) { tfp = tmp->next; if (tmp->offset >= end) break; /* no overlaps at all */ i = end - next->offset; /* overlap is 'i' bytes */ tmp->len -= i; /* so reduce size of */ tmp->offset += i; /* next fragment */ tmp->ptr += i; /* * If we get a frag size of <= 0, remove it and the packet * that it goes with. * * We never throw the new frag away, so the frag being * dumped has always been charged for. */ if (tmp->len <= 0) { if (tmp->prev != NULL) tmp->prev->next = tmp->next; else qp->fragments = tmp->next; if (tmp->next != NULL) tmp->next->prev = tmp->prev; next=tfp; /* We have killed the original next frame */ frag_kfree_skb(tmp->skb,FREE_READ); frag_kfree_s(tmp, sizeof(struct ipfrag)); } } /* * Insert this fragment in the chain of fragments. */ tfp = NULL; if(offset<end) tfp = ip_frag_create(offset, end, skb, ptr); /* * No memory to save the fragment - so throw the lot. If we * failed the frag_create we haven't charged the queue. */ if (!tfp) { skb->sk = NULL; kfree_skb(skb, FREE_READ); return NULL; } /* * From now on our buffer is charged to the queues. */ tfp->prev = prev; tfp->next = next; if (prev != NULL) prev->next = tfp; else qp->fragments = tfp; if (next != NULL) next->prev = tfp; /* * OK, so we inserted this new fragment into the chain. * Check if we now have a full IP datagram which we can * bump up to the IP layer... */ if (ip_done(qp)) { skb2 = ip_glue(qp); /* glue together the fragments */ return(skb2); } return(NULL); }
int icmp_rcv(struct sk_buff *skb, struct device *dev, struct options *opt, __u32 daddr, unsigned short len, __u32 saddr, int redo, struct inet_protocol *protocol) { struct icmphdr *icmph=(void *)skb->h.raw; #ifdef CONFIG_IP_TRANSPARENT_PROXY int r; #endif icmp_statistics.IcmpInMsgs++; if(len < sizeof(struct icmphdr)) { icmp_statistics.IcmpInErrors++; NETDEBUG(printk(KERN_INFO "ICMP: runt packet\n")); kfree_skb(skb, FREE_READ); return 0; } /* * Validate the packet */ if (ip_compute_csum((unsigned char *) icmph, len)) { /* Failed checksum! */ icmp_statistics.IcmpInErrors++; NETDEBUG(printk(KERN_INFO "ICMP: failed checksum from %s!\n", in_ntoa(saddr))); kfree_skb(skb, FREE_READ); return(0); } /* * 18 is the highest 'known' ICMP type. Anything else is a mystery * * RFC 1122: 3.2.2 Unknown ICMP messages types MUST be silently discarded. */ if(icmph->type > 18) { icmp_statistics.IcmpInErrors++; /* Is this right - or do we ignore ? */ kfree_skb(skb,FREE_READ); return(0); } /* * Parse the ICMP message */ #ifdef CONFIG_IP_TRANSPARENT_PROXY /* * We may get non-local addresses and still want to handle them * locally, due to transparent proxying. * Thus, narrow down the test to what is really meant. */ if (daddr!=dev->pa_addr && ((r = ip_chk_addr(daddr)) == IS_BROADCAST || r == IS_MULTICAST)) #else if (daddr && daddr!=dev->pa_addr && ip_chk_addr(daddr) != IS_MYADDR) #endif { /* * RFC 1122: 3.2.2.6 An ICMP_ECHO to broadcast MAY be silently ignored (we don't as it is used * by some network mapping tools). * RFC 1122: 3.2.2.8 An ICMP_TIMESTAMP MAY be silently discarded if to broadcast/multicast. */ if (icmph->type != ICMP_ECHO) { icmp_statistics.IcmpInErrors++; kfree_skb(skb, FREE_READ); return(0); } /* * Reply the multicast/broadcast using a legal * interface - in this case the device we got * it from. */ daddr=dev->pa_addr; } len-=sizeof(struct icmphdr); (*icmp_pointers[icmph->type].input)++; (icmp_pointers[icmph->type].handler)(icmph,skb,skb->dev,saddr,daddr,len); return 0; }
int masq_vdolive_out (struct ip_masq_app *mapp, struct ip_masq *ms, struct sk_buff **skb_p, struct device *dev) { struct sk_buff *skb; struct iphdr *iph; struct tcphdr *th; char *data, *data_limit; unsigned int tagval; /* This should be a 32 bit quantity */ struct ip_masq *n_ms; struct vdolive_priv_data *priv = (struct vdolive_priv_data *)ms->app_data; /* This doesn't work at all if no priv data was allocated on startup */ if (!priv) return 0; /* Everything running correctly already */ if (priv->state == 3) return 0; skb = *skb_p; iph = skb->h.iph; th = (struct tcphdr *)&(((char *)iph)[iph->ihl*4]); data = (char *)&th[1]; data_limit = skb->h.raw + skb->len; if (data+8 > data_limit) { #if DEBUG_CONFIG_IP_MASQ_VDOLIVE printk("VDOlive: packet too short for ID %lx %lx\n", data, data_limit); #endif return 0; } memcpy(&tagval, data+4, 4); #if DEBUG_CONFIG_IP_MASQ_VDOLIVE printk("VDOlive: packet seen, tag %ld, in initial state %d\n", ntohl(tagval), priv->state); #endif /* Check for leading packet ID */ if ((ntohl(tagval) != 6) && (ntohl(tagval) != 1)) { #if DEBUG_CONFIG_IP_MASQ_VDOLIVE printk("VDOlive: unrecognised tag %ld, in initial state %d\n", ntohl(tagval), priv->state); #endif return 0; } /* Check packet is long enough for data - ignore if not */ if ((ntohl(tagval) == 6) && (data+36 > data_limit)) { #if DEBUG_CONFIG_IP_MASQ_VDOLIVE printk("VDOlive: initial packet too short %lx %lx\n", data, data_limit); #endif return 0; } else if ((ntohl(tagval) == 1) && (data+20 > data_limit)) { #if DEBUG_CONFIG_IP_MASQ_VDOLIVE printk("VDOlive: secondary packet too short %lx %lx\n", data, data_limit); #endif return 0; } /* Adjust data pointers */ /* * I could check the complete protocol version tag * in here however I am just going to look for the * "VDO Live" tag in the hope that this part will * remain constant even if the version changes */ if (ntohl(tagval) == 6) { data += 24; #if DEBUG_CONFIG_IP_MASQ_VDOLIVE printk("VDOlive: initial packet found\n"); #endif } else { data += 8; #if DEBUG_CONFIG_IP_MASQ_VDOLIVE printk("VDOlive: secondary packet found\n"); #endif } if (memcmp(data, "VDO Live", 8) != 0) { #if DEBUG_CONFIG_IP_MASQ_VDOLIVE printk("VDOlive: did not find tag\n"); #endif return 0; } /* * The port number is the next word after the tag. * VDOlive encodes all of these values * in 32 bit words, so in this case I am * skipping the first 2 bytes of the next * word to get to the relevant 16 bits */ data += 10; /* * If we have not seen the port already, * set the masquerading tunnel up */ if (!priv->origport) { memcpy(&priv->origport, data, 2); #if DEBUG_CONFIG_IP_MASQ_VDOLIVE printk("VDOlive: found port %d\n", ntohs(priv->origport)); #endif /* Open up a tunnel */ n_ms = ip_masq_new(dev, IPPROTO_UDP, ms->saddr, priv->origport, ms->daddr, 0, IP_MASQ_F_NO_DPORT); if (n_ms==NULL) { printk("VDOlive: unable to build UDP tunnel for %x:%x\n", ms->saddr, priv->origport); /* Leave state as unset */ priv->origport = 0; return 0; } ip_masq_set_expire(n_ms, ip_masq_expire->udp_timeout); priv->masqport = n_ms->mport; } else if (memcmp(data, &(priv->origport), 2)) { printk("VDOlive: ports do not match\n"); /* Write the port in anyhow!!! */ } /* * Write masq port into packet */ memcpy(data, &(priv->masqport), 2); #if DEBUG_CONFIG_IP_MASQ_VDOLIVE printk("VDOlive: rewrote port %d to %d, server %s\n", ntohs(priv->origport), ntohs(priv->masqport), in_ntoa(ms->saddr)); #endif /* * Set state bit to make which bit has been done */ priv->state |= (ntohl(tagval) == 6) ? 1 : 2; return 0; }
static void icmp_unreach(struct icmphdr *icmph, struct sk_buff *skb, struct device *dev, __u32 saddr, __u32 daddr, int len) { struct iphdr *iph; int hash; struct inet_protocol *ipprot; unsigned char *dp; int match_addr=0; if(len<sizeof(struct iphdr)) goto flush_it; iph = (struct iphdr *) (icmph + 1); len-=iph->ihl<<2; if(len<0) goto flush_it; dp= ((unsigned char *)iph)+(iph->ihl<<2); if(icmph->type==ICMP_DEST_UNREACH) { switch(icmph->code & 15) { case ICMP_NET_UNREACH: break; case ICMP_HOST_UNREACH: break; case ICMP_PROT_UNREACH: NETDEBUG(printk(KERN_INFO "ICMP: %s:%d: protocol unreachable.\n", in_ntoa(iph->daddr), (int)iph->protocol)); /* Drop through */ case ICMP_PORT_UNREACH: match_addr=1; break; case ICMP_FRAG_NEEDED: #ifdef CONFIG_NO_PATH_MTU_DISCOVERY NETDEBUG(printk(KERN_INFO "ICMP: %s: fragmentation needed and DF set.\n", in_ntoa(iph->daddr))); break; #else { unsigned short old_mtu = ntohs(iph->tot_len); unsigned short new_mtu = ntohs(icmph->un.echo.sequence); /* * RFC1191 5. 4.2BSD based router can return incorrect * Total Length. If current mtu is unknown or old_mtu * is not less than current mtu, reduce old_mtu by 4 times * the header length. */ if (skb->sk == NULL /* can this happen? */ || skb->sk->ip_route_cache == NULL || skb->sk->ip_route_cache->rt_mtu <= old_mtu) { NETDEBUG(printk(KERN_INFO "4.2BSD based fragmenting router between here and %s, mtu corrected from %d", in_ntoa(iph->daddr), old_mtu)); old_mtu -= 4 * iph->ihl; NETDEBUG(printk(" to %d\n", old_mtu)); } if (new_mtu < 68 || new_mtu >= old_mtu) { /* * It is either dumb router, which does not * understand Path MTU Disc. protocol * or broken (f.e. Linux<=1.3.37 8) router. * Try to guess... * The table is taken from RFC-1191. */ if (old_mtu > 32000) new_mtu = 32000; else if (old_mtu > 17914) new_mtu = 17914; else if (old_mtu > 8166) new_mtu = 8166; else if (old_mtu > 4352) new_mtu = 4352; else if (old_mtu > 2002) new_mtu = 2002; else if (old_mtu > 1492) new_mtu = 1492; else if (old_mtu > 576) new_mtu = 576; else if (old_mtu > 296) new_mtu = 296; /* * These two are not from the RFC but * are needed for AMPRnet AX.25 paths. */ else if (old_mtu > 216) new_mtu = 216; else if (old_mtu > 128) new_mtu = 128; else /* * Despair.. */ new_mtu = 68; } /* * Ugly trick to pass MTU to protocol layer. * Really we should add argument "info" to error handler. */ iph->id = htons(new_mtu); break; } #endif case ICMP_SR_FAILED: NETDEBUG(printk(KERN_INFO "ICMP: %s: Source Route Failed.\n", in_ntoa(iph->daddr))); break; default: break; } if(icmph->code>NR_ICMP_UNREACH) /* Invalid type */ goto flush_it; } /* * Throw it at our lower layers * * RFC 1122: 3.2.2 MUST extract the protocol ID from the passed header. * RFC 1122: 3.2.2.1 MUST pass ICMP unreach messages to the transport layer. * RFC 1122: 3.2.2.2 MUST pass ICMP time expired messages to transport layer. * * Rule: Require port unreachable and protocol unreachable come * from the host in question. Stop junk spoofs. */ if(!match_addr || saddr == iph->daddr) { /* * Get the protocol(s). */ hash = iph->protocol & (MAX_INET_PROTOS -1); /* * This can't change while we are doing it. */ ipprot = (struct inet_protocol *) inet_protos[hash]; while(ipprot != NULL) { struct inet_protocol *nextip; nextip = (struct inet_protocol *) ipprot->next; /* * Pass it off to everyone who wants it. */ /* RFC1122: OK. Passes appropriate ICMP errors to the */ /* appropriate protocol layer (MUST), as per 3.2.2. */ if (iph->protocol == ipprot->protocol && ipprot->err_handler) { ipprot->err_handler(icmph->type, icmph->code, dp, iph->daddr, iph->saddr, ipprot, len); } ipprot = nextip; } } flush_it: kfree_skb(skb, FREE_READ); }
/* * Get the Hardware address of a given IP number. * Gracefully stolen from Diald. */ static int GetEtherHWaddr (unsigned int ipaddr, struct sockaddr *hwaddr) { struct ifreq *ifr, *ifend; unsigned int ina, mask; struct ifreq ifreq; struct ifconf ifc; struct ifreq ifs[MAX_IFS]; int SockFD; SockFD = socket(AF_INET, SOCK_DGRAM, 0); ifc.ifc_len = sizeof(ifs); ifc.ifc_req = ifs; if (ioctl(SockFD, SIOCGIFCONF, &ifc) < 0) { printf("ioctl(SIOCGIFCONF): %m\n"); return 0; } /* * Scan through looking for an interface with an Internet * address on the same subnet as `ipaddr'. */ ifend = ifs + (ifc.ifc_len / sizeof(struct ifreq)); for (ifr = ifc.ifc_req; ifr < ifend; ifr++) { if (ifr->ifr_addr.sa_family == AF_INET) { ina = ((struct sockaddr_in *) &ifr->ifr_addr)->sin_addr.s_addr; strncpy(ifreq.ifr_name, ifr->ifr_name, sizeof(ifreq.ifr_name)); /* * Check that the interface is up, and not point-to-point * nor loopback. */ if (ioctl(SockFD, SIOCGIFFLAGS, &ifreq) < 0) continue; if (((ifreq.ifr_flags ^ FLAGS_GOOD) & FLAGS_MASK) != 0) continue; /* * Get its netmask and check that it's on the right subnet. */ if (ioctl(SockFD, SIOCGIFNETMASK, &ifreq) < 0) continue; mask = ((struct sockaddr_in *) &ifreq.ifr_addr)->sin_addr.s_addr; if (((ipaddr ^ ina) & mask) != 0) continue; break; } } if (ifr >= ifend) return 0; /* * Finally get the hardware address. */ memset (&ifreq.ifr_hwaddr, 0, sizeof (struct sockaddr)); if (ioctl (SockFD, SIOCGIFHWADDR, &ifreq) < 0) { printf("SIOCGIFHWADDR(%s): %m\n", ifreq.ifr_name); return 0; } memcpy (hwaddr, &ifreq.ifr_hwaddr, sizeof (struct sockaddr)); printf("MacGate: Using Device %s, IP %s -> Ethernet %02x:%02x:%02x:%02x:%02x:%02x\n", ifreq.ifr_name, in_ntoa(ina), (int) ((unsigned char *) &ifreq.ifr_hwaddr.sa_data)[0], (int) ((unsigned char *) &ifreq.ifr_hwaddr.sa_data)[1], (int) ((unsigned char *) &ifreq.ifr_hwaddr.sa_data)[2], (int) ((unsigned char *) &ifreq.ifr_hwaddr.sa_data)[3], (int) ((unsigned char *) &ifreq.ifr_hwaddr.sa_data)[4], (int) ((unsigned char *) &ifreq.ifr_hwaddr.sa_data)[5]); return 1; }
static struct sk_buff *ip_glue(struct ipq *qp) { struct sk_buff *skb; struct iphdr *iph; struct ipfrag *fp; unsigned char *ptr; int count, len; /* * Allocate a new buffer for the datagram. */ len = qp->ihlen + qp->len; if(len>65535) { NETDEBUG(printk("Oversized IP packet from %s.\n", in_ntoa(qp->iph->saddr))); ip_statistics.IpReasmFails++; ip_free(qp); return NULL; } if ((skb = dev_alloc_skb(len)) == NULL) { ip_statistics.IpReasmFails++; NETDEBUG(printk("IP: queue_glue: no memory for gluing queue %p\n", qp)); ip_free(qp); return(NULL); } /* Fill in the basic details. */ skb_put(skb,len); skb->h.raw = skb->data; skb->free = 1; /* Copy the original IP headers into the new buffer. */ ptr = (unsigned char *) skb->h.raw; memcpy(ptr, ((unsigned char *) qp->iph), qp->ihlen); ptr += qp->ihlen; count = 0; /* Copy the data portions of all fragments into the new buffer. */ fp = qp->fragments; while(fp != NULL) { if (fp->len < 0 || fp->offset+qp->ihlen+fp->len > skb->len) { NETDEBUG(printk("Invalid fragment list: Fragment over size.\n")); ip_free(qp); kfree_skb(skb,FREE_WRITE); ip_statistics.IpReasmFails++; return NULL; } memcpy((ptr + fp->offset), fp->ptr, fp->len); count += fp->len; fp = fp->next; } skb->pkt_type = qp->fragments->skb->pkt_type; skb->protocol = qp->fragments->skb->protocol; /* We glued together all fragments, so remove the queue entry. */ ip_free(qp); /* Done with all fragments. Fixup the new IP header. */ iph = skb->h.iph; iph->frag_off = 0; iph->tot_len = htons((iph->ihl * 4) + count); skb->ip_hdr = iph; ip_statistics.IpReasmOKs++; return(skb); }