static int udp_manip_pkt(struct sk_buff **pskb, unsigned int hdroff, const struct ip_conntrack_manip *manip, enum ip_nat_manip_type maniptype) { struct udphdr *hdr; u_int32_t oldip; u_int16_t *portptr; if (!skb_ip_make_writable(pskb, hdroff + sizeof(hdr))) return 0; hdr = (void *)(*pskb)->data + hdroff; if (maniptype == IP_NAT_MANIP_SRC) { /* Get rid of src ip and src pt */ oldip = (*pskb)->nh.iph->saddr; portptr = &hdr->source; } else { /* Get rid of dst ip and dst pt */ oldip = (*pskb)->nh.iph->daddr; portptr = &hdr->dest; } if (hdr->check) /* 0 is a special case meaning no checksum */ hdr->check = ip_nat_cheat_check(~oldip, manip->ip, ip_nat_cheat_check(*portptr ^ 0xFFFF, manip->u.udp.port, hdr->check)); *portptr = manip->u.udp.port; return 1; }
static void tcp_manip_pkt(struct iphdr *iph, size_t len, const struct ip_conntrack_manip *manip, enum ip_nat_manip_type maniptype) { struct tcphdr *hdr = (struct tcphdr *)((u_int32_t *)iph + iph->ihl); u_int32_t oldip; u_int16_t *portptr; if (maniptype == IP_NAT_MANIP_SRC) { /* Get rid of src ip and src pt */ oldip = iph->saddr; portptr = &hdr->source; } else { /* Get rid of dst ip and dst pt */ oldip = iph->daddr; portptr = &hdr->dest; } /* this could be a inner header returned in icmp packet; in such cases we cannot update the checksum field since it is outside of the 8 bytes of transport layer headers we are guaranteed */ if(((void *)&hdr->check + sizeof(hdr->check) - (void *)iph) <= len) { hdr->check = ip_nat_cheat_check(~oldip, manip->ip, ip_nat_cheat_check(*portptr ^ 0xFFFF, manip->u.tcp.port, hdr->check)); } *portptr = manip->u.tcp.port; }
static void udp_manip_pkt(struct iphdr *iph, size_t len, const struct ip_conntrack_manip *manip, enum ip_nat_manip_type maniptype) { struct udphdr *hdr = (struct udphdr *)((u_int32_t *)iph + iph->ihl); u_int32_t oldip; u_int16_t *portptr; if (maniptype == IP_NAT_MANIP_SRC) { /* Get rid of src ip and src pt */ oldip = iph->saddr; portptr = &hdr->source; } else { /* Get rid of dst ip and dst pt */ oldip = iph->daddr; portptr = &hdr->dest; } if (hdr->check) /* 0 is a special case meaning no checksum */ hdr->check = ip_nat_cheat_check(~oldip, manip->ip, ip_nat_cheat_check(*portptr ^ 0xFFFF, manip->u.udp.port, hdr->check)); *portptr = manip->u.udp.port; }
static int tcp_manip_pkt(struct sk_buff **pskb, unsigned int iphdroff, const struct ip_conntrack_tuple *tuple, enum ip_nat_manip_type maniptype) { struct iphdr *iph = (struct iphdr *)((*pskb)->data + iphdroff); struct tcphdr *hdr; unsigned int hdroff = iphdroff + iph->ihl*4; u32 oldip, newip; u16 *portptr, newport, oldport; int hdrsize = 8; /* TCP connection tracking guarantees this much */ /* this could be a inner header returned in icmp packet; in such cases we cannot update the checksum field since it is outside of the 8 bytes of transport layer headers we are guaranteed */ if ((*pskb)->len >= hdroff + sizeof(struct tcphdr)) hdrsize = sizeof(struct tcphdr); if (!skb_make_writable(pskb, hdroff + hdrsize)) return 0; iph = (struct iphdr *)((*pskb)->data + iphdroff); hdr = (struct tcphdr *)((*pskb)->data + hdroff); if (maniptype == IP_NAT_MANIP_SRC) { /* Get rid of src ip and src pt */ oldip = iph->saddr; newip = tuple->src.ip; newport = tuple->src.u.tcp.port; portptr = &hdr->source; } else { /* Get rid of dst ip and dst pt */ oldip = iph->daddr; newip = tuple->dst.ip; newport = tuple->dst.u.tcp.port; portptr = &hdr->dest; } oldport = *portptr; *portptr = newport; if (hdrsize < sizeof(*hdr)) return 1; hdr->check = ip_nat_cheat_check(~oldip, newip, ip_nat_cheat_check(oldport ^ 0xFFFF, newport, hdr->check)); return 1; }
static int udp_manip_pkt(struct sk_buff **pskb, unsigned int iphdroff, const struct ip_conntrack_tuple *tuple, enum ip_nat_manip_type maniptype) { struct iphdr *iph = (struct iphdr *)((*pskb)->data + iphdroff); struct udphdr *hdr; unsigned int hdroff = iphdroff + iph->ihl*4; u32 oldip, newip; u16 *portptr, newport; if (!skb_make_writable(pskb, hdroff + sizeof(*hdr))) return 0; iph = (struct iphdr *)((*pskb)->data + iphdroff); hdr = (struct udphdr *)((*pskb)->data + hdroff); if (maniptype == IP_NAT_MANIP_SRC) { /* Get rid of src ip and src pt */ oldip = iph->saddr; newip = tuple->src.ip; newport = tuple->src.u.udp.port; portptr = &hdr->source; } else { /* Get rid of dst ip and dst pt */ oldip = iph->daddr; newip = tuple->dst.ip; newport = tuple->dst.u.udp.port; portptr = &hdr->dest; } if (hdr->check) { /* 0 is a special case meaning no checksum */ #ifdef CONFIG_XEN if ((*pskb)->proto_csum_blank) hdr->check = ip_nat_cheat_check(oldip, ~newip, hdr->check); else #endif hdr->check = ip_nat_cheat_check(~oldip, newip, ip_nat_cheat_check(*portptr ^ 0xFFFF, newport, hdr->check)); } *portptr = newport; return 1; }
/* manipulate a GRE packet according to maniptype */ static int gre_manip_pkt(struct sk_buff **pskb, unsigned int iphdroff, const struct ip_conntrack_tuple *tuple, enum ip_nat_manip_type maniptype) { struct gre_hdr *greh; struct gre_hdr_pptp *pgreh; struct iphdr *iph = (struct iphdr *)((*pskb)->data + iphdroff); unsigned int hdroff = iphdroff + iph->ihl*4; /* pgreh includes two optional 32bit fields which are not required * to be there. That's where the magic '8' comes from */ if (!skb_make_writable(pskb, hdroff + sizeof(*pgreh)-8)) return 0; greh = (void *)(*pskb)->data + hdroff; pgreh = (struct gre_hdr_pptp *) greh; /* we only have destination manip of a packet, since 'source key' * is not present in the packet itself */ if (maniptype == IP_NAT_MANIP_DST) { /* key manipulation is always dest */ switch (greh->version) { case 0: if (!greh->key) { DEBUGP("can't nat GRE w/o key\n"); break; } if (greh->csum) { /* FIXME: Never tested this code... */ *(gre_csum(greh)) = ip_nat_cheat_check(~*(gre_key(greh)), tuple->dst.u.gre.key, *(gre_csum(greh))); } *(gre_key(greh)) = tuple->dst.u.gre.key; break; case GRE_VERSION_PPTP: DEBUGP("call_id -> 0x%04x\n", ntohs(tuple->dst.u.gre.key)); pgreh->call_id = tuple->dst.u.gre.key; break; default: DEBUGP("can't nat unknown GRE version\n"); return 0; break; } } return 1; }
/* manipulate a GRE packet according to maniptype */ static void gre_manip_pkt(struct iphdr *iph, size_t len, const struct ip_conntrack_manip *manip, enum ip_nat_manip_type maniptype) { struct gre_hdr *greh = (struct gre_hdr *)((u_int32_t *)iph+iph->ihl); struct gre_hdr_pptp *pgreh = (struct gre_hdr_pptp *) greh; /* we only have destination manip of a packet, since 'source key' * is not present in the packet itself */ if (maniptype == IP_NAT_MANIP_DST) { /* key manipulation is always dest */ switch (greh->version) { case 0: if (!greh->key) { DEBUGP("can't nat GRE w/o key\n"); break; } if (greh->csum) { /* FIXME: Never tested this code... */ *(gre_csum(greh)) = ip_nat_cheat_check(~*(gre_key(greh)), manip->u.gre.key, *(gre_csum(greh))); } *(gre_key(greh)) = manip->u.gre.key; break; case GRE_VERSION_PPTP: DEBUGP("call_id -> 0x%04x\n", ntohl(manip->u.gre.key)); pgreh->call_id = htons(ntohl(manip->u.gre.key)); break; default: DEBUGP("can't nat unknown GRE version\n"); break; } } }
int udp_user_read(int fd, void *buf, int len, struct udp_data *pri) { char buffer[BUF_SIZE], *udpStart = buffer + sizeof(struct iphdr); CHECK_SOCKET(fd); #ifdef INCLUDE_MAC #error INCLUDE_MAC support does not work #endif const int invalidPacketLen = -1; struct sockaddr_in srcAddr; int srcAddrLen = sizeof(struct sockaddr_in); int rcv_packet_len = invalidPacketLen; __u32 srcIP; if ((rcv_packet_len = recvfrom(fd, udpStart, BUF_SIZE, 0, (struct sockaddr *) & srcAddr, &srcAddrLen)) <= 0) { //DEBUG(1, "recvfrom"); return 0; } srcIP = srcAddr.sin_addr.s_addr; if(rcv_packet_len > 0) { DEBUG(2,"Packet recv'd(%d); need to perform unwrap operation\n", rcv_packet_len); /* XXX Copy unwrap code from kernel-level skbuff reorg stuff * */ struct ipudp *iuh = (struct ipudp *)udpStart; char *dataStart = (char*)(iuh + 1); struct iphdr *iph = ((struct iphdr*)dataStart) - 1; struct tcphdr *th = (struct tcphdr *)dataStart; int cookedLen = rcv_packet_len - sizeof(struct ipudp) + sizeof(struct iphdr); if(cookedLen < sizeof(struct tcphdr)) { printk("Cooked length is shorter than minimum tcp " "header len\n"); return 0; } __u16 origCheck = th->check; // This code does NOT respect the ipudp src and dest addresses // Remove UDP header; push on IP header if(iuh->saddr != srcIP) { #ifndef SUPPORT_NAT addrPrintComp("IPUDP header src did not match addr", "!=",iuh->saddr, srcIP); return 0; #else // th->check adjustment needed th->check = ip_nat_cheat_check(~iuh->saddr, srcIP, th->check); #endif } if(iuh->daddr != pri->local_addr) { #ifndef SUPPORT_NAT addrPrintComp("IPUDP header dest did not match addr", "!=",iuh->daddr, pri->local_addr); return 0; #else // th->check adjustment needed th->check = ip_nat_cheat_check(~iuh->daddr, pri->local_addr, th->check); #endif } int ihl = sizeof(*iph); iph->version = 4; iph->ihl = ihl / 4; iph->tos = 0; iph->tot_len = htons(cookedLen); static int ip_id = 0; iph->id = ip_id++; iph->frag_off = 0; iph->ttl = 255; iph->protocol = IPPROTO_TCP; iph->check = 0; #ifdef SUPPORT_NAT iph->saddr = srcIP; iph->daddr = pri->local_addr; #else iph->saddr = iuh->saddr; iph->daddr = iuh->daddr; #endif iph->check = ip_compute_csum((unsigned char *)iph, ihl); // XXX should copy protocol from an ipudp field DEBUG(2,"Returning cooked length %d, " "origCheck = %d, newCheck = %d\n", cookedLen, origCheck, th->check); DEBUG_GUARD(2, printk("IPH: "); hexdump((char*)iph, ihl) ); memcpy(buf, (char*)iph, cookedLen); return(cookedLen); }