static int irc_data_fixup(const struct ip_ct_irc_expect *exp_irc_info, struct ip_conntrack *ct, struct sk_buff **pskb, enum ip_conntrack_info ctinfo, struct ip_conntrack_expect *expect) { u_int32_t newip; struct ip_conntrack_tuple t; struct iphdr *iph = (*pskb)->nh.iph; struct tcphdr *tcph = (void *) iph + iph->ihl * 4; u_int16_t port; /* "4294967296 65635 " */ char buffer[18]; DEBUGP("IRC_NAT: info (seq %u + %u) in %u\n", expect->seq, exp_irc_info->len, ntohl(tcph->seq)); newip = ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip; /* Alter conntrack's expectations. */ t = expect->tuple; t.dst.ip = newip; for (port = exp_irc_info->port; port != 0; port++) { t.dst.u.tcp.port = htons(port); if (ip_conntrack_change_expect(expect, &t) == 0) { DEBUGP("using port %d", port); break; } } if (port == 0) return 0; /* strlen("\1DCC CHAT chat AAAAAAAA P\1\n")=27 * strlen("\1DCC SCHAT chat AAAAAAAA P\1\n")=28 * strlen("\1DCC SEND F AAAAAAAA P S\1\n")=26 * strlen("\1DCC MOVE F AAAAAAAA P S\1\n")=26 * strlen("\1DCC TSEND F AAAAAAAA P S\1\n")=27 * AAAAAAAAA: bound addr (1.0.0.0==16777216, min 8 digits, * 255.255.255.255==4294967296, 10 digits) * P: bound port (min 1 d, max 5d (65635)) * F: filename (min 1 d ) * S: size (min 1 d ) * 0x01, \n: terminators */ sprintf(buffer, "%u %u", ntohl(newip), port); DEBUGP("ip_nat_irc: Inserting '%s' == %u.%u.%u.%u, port %u\n", buffer, NIPQUAD(newip), port); return ip_nat_mangle_tcp_packet(pskb, ct, ctinfo, expect->seq - ntohl(tcph->seq), exp_irc_info->len, buffer, strlen(buffer)); }
static int set_addr(struct sk_buff **pskb, unsigned char **data, int dataoff, unsigned int addroff, __be32 ip, u_int16_t port) { enum ip_conntrack_info ctinfo; struct ip_conntrack *ct = ip_conntrack_get(*pskb, &ctinfo); struct { __be32 ip; __be16 port; } __attribute__ ((__packed__)) buf; struct tcphdr _tcph, *th; buf.ip = ip; buf.port = htons(port); addroff += dataoff; if ((*pskb)->nh.iph->protocol == IPPROTO_TCP) { if (!ip_nat_mangle_tcp_packet(pskb, ct, ctinfo, addroff, sizeof(buf), (char *) &buf, sizeof(buf))) { if (net_ratelimit()) printk("ip_nat_h323: ip_nat_mangle_tcp_packet" " error\n"); return -1; } /* Relocate data pointer */ th = skb_header_pointer(*pskb, (*pskb)->nh.iph->ihl * 4, sizeof(_tcph), &_tcph); if (th == NULL) return -1; *data = (*pskb)->data + (*pskb)->nh.iph->ihl * 4 + th->doff * 4 + dataoff; } else { if (!ip_nat_mangle_udp_packet(pskb, ct, ctinfo, addroff, sizeof(buf), (char *) &buf, sizeof(buf))) { if (net_ratelimit()) printk("ip_nat_h323: ip_nat_mangle_udp_packet" " error\n"); return -1; } /* ip_nat_mangle_udp_packet uses skb_make_writable() to copy * or pull everything in a linear buffer, so we can safely * use the skb pointers now */ *data = (*pskb)->data + (*pskb)->nh.iph->ihl * 4 + sizeof(struct udphdr); } return 0; }
static int sl_remove_port(struct sk_buff **pskb, struct ip_conntrack *ct, enum ip_conntrack_info ctinfo, unsigned int host_offset, unsigned int dataoff, unsigned int datalen, unsigned int end_of_host, unsigned char *user_data) { if (strncmp(search[PORT].string, &user_data[end_of_host-search[PORT].len+search[NEWLINE].len], search[PORT].len)) { #ifdef SL_DEBUG printk(KERN_DEBUG "no port rewrite found in packet strncmp\n"); printk(KERN_DEBUG "end of host packet dump:\n%s\n", (unsigned char *)((unsigned int)user_data+end_of_host-search[PORT].len+search[NEWLINE].len)); #endif return 0; } #ifdef SL_DEBUG printk(KERN_DEBUG "remove_port found a port at offset %u\n", end_of_host-search[PORT].len+search[NEWLINE].len ); #endif /* remove the port */ if (!ip_nat_mangle_tcp_packet(pskb, ct, ctinfo, end_of_host-search[PORT].len+search[NEWLINE].len, search[PORT].len-(search[NEWLINE].len*2), // subtract \r\n NULL, 0)) { printk(KERN_ERR "unable to remove port needle\n"); // we've already found the port, so we return 1 regardless return 1; } #ifdef SL_DEBUG printk(KERN_DEBUG "port removed ok, new packet\n%s\n", (unsigned char *)user_data); #endif return 1; }
static int mangle_packet(struct sk_buff **pskb, u_int32_t newip, unsigned int matchoff, unsigned int matchlen, struct ip_conntrack *ct, enum ip_conntrack_info ctinfo) { unsigned char buffer[4]; MUST_BE_LOCKED(&ip_sc_lock); *((u_int32_t *)(buffer)) = htonl(newip); DEBUGP("calling ip_nat_mangle_tcp_packet\n"); return ip_nat_mangle_tcp_packet(pskb, ct, ctinfo, matchoff, matchlen, buffer, 4); }
/* |1|132.235.1.2|6275| */ static int mangle_epsv_packet(struct sk_buff **pskb, u_int32_t newip, u_int16_t port, unsigned int matchoff, unsigned int matchlen, struct ip_conntrack *ct, enum ip_conntrack_info ctinfo, u32 *seq) { char buffer[sizeof("|||65535|")]; sprintf(buffer, "|||%u|", port); DEBUGP("calling ip_nat_mangle_tcp_packet\n"); *seq += strlen(buffer) - matchlen; return ip_nat_mangle_tcp_packet(pskb, ct, ctinfo, matchoff, matchlen, buffer, strlen(buffer)); }
static int mangle_rfc959_packet(struct sk_buff **pskb, u_int32_t newip, u_int16_t port, unsigned int matchoff, unsigned int matchlen, struct ip_conntrack *ct, enum ip_conntrack_info ctinfo, u32 *seq) { char buffer[sizeof("nnn,nnn,nnn,nnn,nnn,nnn")]; sprintf(buffer, "%u,%u,%u,%u,%u,%u", NIPQUAD(newip), port>>8, port&0xFF); DEBUGP("calling ip_nat_mangle_tcp_packet\n"); *seq += strlen(buffer) - matchlen; return ip_nat_mangle_tcp_packet(pskb, ct, ctinfo, matchoff, matchlen, buffer, strlen(buffer)); }
/* inbound packets == from PAC to PNS */ static int pptp_inbound_pkt(struct sk_buff **pskb, struct ip_conntrack *ct, enum ip_conntrack_info ctinfo, struct PptpControlHeader *ctlh, union pptp_ctrl_union *pptpReq) { struct ip_nat_pptp *nat_pptp_info = &ct->nat.help.nat_pptp_info; u_int16_t msg, new_cid = 0, new_pcid; unsigned int pcid_off, cid_off = 0; int ret = NF_ACCEPT, rv; new_pcid = htons(nat_pptp_info->pns_call_id); switch (msg = ntohs(ctlh->messageType)) { case PPTP_OUT_CALL_REPLY: pcid_off = offsetof(union pptp_ctrl_union, ocack.peersCallID); cid_off = offsetof(union pptp_ctrl_union, ocack.callID); break; case PPTP_IN_CALL_CONNECT: pcid_off = offsetof(union pptp_ctrl_union, iccon.peersCallID); break; case PPTP_IN_CALL_REQUEST: /* only need to nat in case PAC is behind NAT box */ return NF_ACCEPT; case PPTP_WAN_ERROR_NOTIFY: pcid_off = offsetof(union pptp_ctrl_union, wanerr.peersCallID); break; case PPTP_CALL_DISCONNECT_NOTIFY: pcid_off = offsetof(union pptp_ctrl_union, disc.callID); break; case PPTP_SET_LINK_INFO: pcid_off = offsetof(union pptp_ctrl_union, setlink.peersCallID); break; default: DEBUGP("unknown inbound packet %s\n", (msg <= PPTP_MSG_MAX)? strMName[msg]:strMName[0]); /* fall through */ case PPTP_START_SESSION_REQUEST: case PPTP_START_SESSION_REPLY: case PPTP_STOP_SESSION_REQUEST: case PPTP_STOP_SESSION_REPLY: case PPTP_ECHO_REQUEST: case PPTP_ECHO_REPLY: /* no need to alter packet */ return NF_ACCEPT; } /* only OUT_CALL_REPLY, IN_CALL_CONNECT, IN_CALL_REQUEST, * WAN_ERROR_NOTIFY, CALL_DISCONNECT_NOTIFY pass down here */ /* mangle packet */ IP_NF_ASSERT(pcid); DEBUGP("altering peer call id from 0x%04x to 0x%04x\n", ntohs(*(u_int16_t *)pptpReq + pcid_off), ntohs(new_pcid)); rv = ip_nat_mangle_tcp_packet(pskb, ct, ctinfo, pcid_off + sizeof(struct pptp_pkt_hdr) + sizeof(struct PptpControlHeader), sizeof(new_pcid), (char *)&new_pcid, sizeof(new_pcid)); if (rv != NF_ACCEPT) return rv; if (new_cid) { DEBUGP("altering call id from 0x%04x to 0x%04x\n", ntohs(*(u_int16_t *)pptpReq + cid_off), ntohs(new_cid)); rv = ip_nat_mangle_tcp_packet(pskb, ct, ctinfo, cid_off + sizeof(struct pptp_pkt_hdr) + sizeof(struct PptpControlHeader), sizeof(new_cid), (char *)&new_cid, sizeof(new_cid)); if (rv != NF_ACCEPT) return rv; } /* check for earlier return value of 'switch' above */ if (ret != NF_ACCEPT) return ret; /* great, at least we don't need to resize packets */ return NF_ACCEPT; }
/* outbound packets == from PNS to PAC */ static int pptp_outbound_pkt(struct sk_buff **pskb, struct ip_conntrack *ct, enum ip_conntrack_info ctinfo, struct PptpControlHeader *ctlh, union pptp_ctrl_union *pptpReq) { struct ip_ct_pptp_master *ct_pptp_info = &ct->help.ct_pptp_info; struct ip_nat_pptp *nat_pptp_info = &ct->nat.help.nat_pptp_info; u_int16_t msg, new_callid; unsigned int cid_off; new_callid = htons(ct_pptp_info->pns_call_id); switch (msg = ntohs(ctlh->messageType)) { case PPTP_OUT_CALL_REQUEST: cid_off = offsetof(union pptp_ctrl_union, ocreq.callID); /* FIXME: ideally we would want to reserve a call ID * here. current netfilter NAT core is not able to do * this :( For now we use TCP source port. This breaks * multiple calls within one control session */ /* save original call ID in nat_info */ nat_pptp_info->pns_call_id = ct_pptp_info->pns_call_id; /* don't use tcph->source since we are at a DSTmanip * hook (e.g. PREROUTING) and pkt is not mangled yet */ new_callid = ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.u.tcp.port; /* save new call ID in ct info */ ct_pptp_info->pns_call_id = ntohs(new_callid); break; case PPTP_IN_CALL_REPLY: cid_off = offsetof(union pptp_ctrl_union, icreq.callID); break; case PPTP_CALL_CLEAR_REQUEST: cid_off = offsetof(union pptp_ctrl_union, clrreq.callID); break; default: DEBUGP("unknown outbound packet 0x%04x:%s\n", msg, (msg <= PPTP_MSG_MAX)? strMName[msg]:strMName[0]); /* fall through */ case PPTP_SET_LINK_INFO: /* only need to NAT in case PAC is behind NAT box */ case PPTP_START_SESSION_REQUEST: case PPTP_START_SESSION_REPLY: case PPTP_STOP_SESSION_REQUEST: case PPTP_STOP_SESSION_REPLY: case PPTP_ECHO_REQUEST: case PPTP_ECHO_REPLY: /* no need to alter packet */ return NF_ACCEPT; } /* only OUT_CALL_REQUEST, IN_CALL_REPLY, CALL_CLEAR_REQUEST pass * down to here */ IP_NF_ASSERT(cid); DEBUGP("altering call id from 0x%04x to 0x%04x\n", ntohs(*(u_int16_t *)pptpReq + cid_off), ntohs(new_callid)); /* mangle packet */ if (ip_nat_mangle_tcp_packet(pskb, ct, ctinfo, cid_off + sizeof(struct pptp_pkt_hdr) + sizeof(struct PptpControlHeader), sizeof(new_callid), (char *)&new_callid, sizeof(new_callid)) == 0) return NF_DROP; return NF_ACCEPT; }
static unsigned int help(struct sk_buff **pskb, enum ip_conntrack_info ctinfo, unsigned int matchoff, unsigned int matchlen, struct ip_conntrack_expect *exp) { u_int16_t port; unsigned int ret; /* "4294967296 65635 " */ char buffer[18]; DEBUGP("IRC_NAT: info (seq %u + %u) in %u\n", expect->seq, exp_irc_info->len, ntohl(tcph->seq)); /* Reply comes from server. */ exp->saved_proto.tcp.port = exp->tuple.dst.u.tcp.port; exp->dir = IP_CT_DIR_REPLY; /* When you see the packet, we need to NAT it the same as the * this one. */ exp->expectfn = ip_nat_follow_master; /* Try to get same port: if not, try to change it. */ for (port = ntohs(exp->saved_proto.tcp.port); port != 0; port++) { exp->tuple.dst.u.tcp.port = htons(port); if (ip_conntrack_expect_related(exp) == 0) break; } if (port == 0) return NF_DROP; /* strlen("\1DCC CHAT chat AAAAAAAA P\1\n")=27 * strlen("\1DCC SCHAT chat AAAAAAAA P\1\n")=28 * strlen("\1DCC SEND F AAAAAAAA P S\1\n")=26 * strlen("\1DCC MOVE F AAAAAAAA P S\1\n")=26 * strlen("\1DCC TSEND F AAAAAAAA P S\1\n")=27 * AAAAAAAAA: bound addr (1.0.0.0==16777216, min 8 digits, * 255.255.255.255==4294967296, 10 digits) * P: bound port (min 1 d, max 5d (65635)) * F: filename (min 1 d ) * S: size (min 1 d ) * 0x01, \n: terminators */ /* AAA = "us", ie. where server normally talks to. */ sprintf(buffer, "%u %u", ntohl(exp->master->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip), port); DEBUGP("ip_nat_irc: Inserting '%s' == %u.%u.%u.%u, port %u\n", buffer, NIPQUAD(exp->tuple.src.ip), port); ret = ip_nat_mangle_tcp_packet(pskb, exp->master, ctinfo, matchoff, matchlen, buffer, strlen(buffer)); if (ret != NF_ACCEPT) ip_conntrack_unexpect_related(exp); return ret; }
static int mms_data_fixup(const struct ip_ct_mms_expect *ct_mms_info, struct ip_conntrack *ct, struct sk_buff **pskb, enum ip_conntrack_info ctinfo, struct ip_conntrack_expect *expect) { u_int32_t newip; struct ip_conntrack_tuple t; struct iphdr *iph = (*pskb)->nh.iph; struct tcphdr *tcph = (void *) iph + iph->ihl * 4; char *data = (char *)tcph + tcph->doff * 4; int i, j, k, port; u_int16_t mms_proto; u_int32_t *mms_chunkLenLV = (u_int32_t *)(data + MMS_SRV_CHUNKLENLV_OFFSET); u_int32_t *mms_chunkLenLM = (u_int32_t *)(data + MMS_SRV_CHUNKLENLM_OFFSET); u_int32_t *mms_messageLength = (u_int32_t *)(data + MMS_SRV_MESSAGELENGTH_OFFSET); int zero_padding; char buffer[28]; /* "\\255.255.255.255\UDP\65635" * 2 (for unicode) */ char unicode_buffer[75]; /* 27*2 (unicode) + 20 + 1 */ char proto_string[6]; /* what was the protocol again ? */ mms_proto = expect->tuple.dst.protonum; sprintf(proto_string, "%u", mms_proto); DEBUGP("ip_nat_mms: mms_data_fixup: info (seq %u + %u) in %u, proto %s\n", expect->seq, ct_mms_info->len, ntohl(tcph->seq), mms_proto == IPPROTO_UDP ? "UDP" : mms_proto == IPPROTO_TCP ? "TCP":proto_string); newip = ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip; /* Alter conntrack's expectations. */ t = expect->tuple; t.dst.ip = newip; for (port = ct_mms_info->port; port != 0; port++) { t.dst.u.tcp.port = htons(port); if (ip_conntrack_change_expect(expect, &t) == 0) { DEBUGP("ip_nat_mms: mms_data_fixup: using port %d\n", port); break; } } if(port == 0) return 0; sprintf(buffer, "\\\\%u.%u.%u.%u\\%s\\%u", NIPQUAD(newip), expect->tuple.dst.protonum == IPPROTO_UDP ? "UDP" : expect->tuple.dst.protonum == IPPROTO_TCP ? "TCP":proto_string, port); DEBUGP("ip_nat_mms: new unicode string=%s\n", buffer); memset(unicode_buffer, 0, sizeof(char)*75); for (i=0; i<strlen(buffer); ++i) *(unicode_buffer+i*2)=*(buffer+i); DEBUGP("ip_nat_mms: mms_data_fixup: padding: %u len: %u\n", ct_mms_info->padding, ct_mms_info->len); DEBUGP("ip_nat_mms: mms_data_fixup: offset: %u\n", MMS_SRV_UNICODE_STRING_OFFSET+ct_mms_info->len); DUMP_BYTES(data+MMS_SRV_UNICODE_STRING_OFFSET, 60); /* add end of packet to it */ for (j=0; j<ct_mms_info->padding; ++j) { DEBUGP("ip_nat_mms: mms_data_fixup: i=%u j=%u byte=%u\n", i, j, (u8)*(data+MMS_SRV_UNICODE_STRING_OFFSET+ct_mms_info->len+j)); *(unicode_buffer+i*2+j) = *(data+MMS_SRV_UNICODE_STRING_OFFSET+ct_mms_info->len+j); } /* pad with zeroes at the end ? see explanation of weird math below */ zero_padding = (8-(strlen(buffer)*2 + ct_mms_info->padding + 4)%8)%8; for (k=0; k<zero_padding; ++k) *(unicode_buffer+i*2+j+k)= (char)0; DEBUGP("ip_nat_mms: mms_data_fixup: zero_padding = %u\n", zero_padding); DEBUGP("ip_nat_mms: original=> chunkLenLV=%u chunkLenLM=%u messageLength=%u\n", *mms_chunkLenLV, *mms_chunkLenLM, *mms_messageLength); /* explanation, before I forget what I did: strlen(buffer)*2 + ct_mms_info->padding + 4 must be divisable by 8; divide by 8 and add 3 to compute the mms_chunkLenLM field, but note that things may have to be padded with zeroes to align by 8 bytes, hence we add 7 and divide by 8 to get the correct length */ *mms_chunkLenLM = (u_int32_t) (3+(strlen(buffer)*2+ct_mms_info->padding+11)/8); *mms_chunkLenLV = *mms_chunkLenLM+2; *mms_messageLength = *mms_chunkLenLV*8; DEBUGP("ip_nat_mms: modified=> chunkLenLV=%u chunkLenLM=%u messageLength=%u\n", *mms_chunkLenLV, *mms_chunkLenLM, *mms_messageLength); ip_nat_mangle_tcp_packet(pskb, ct, ctinfo, expect->seq - ntohl(tcph->seq), ct_mms_info->len + ct_mms_info->padding, unicode_buffer, strlen(buffer)*2 + ct_mms_info->padding + zero_padding); DUMP_BYTES(unicode_buffer, 60); return 1; }
static unsigned int add_sl_header(struct sk_buff **pskb, struct ip_conntrack *ct, enum ip_conntrack_info ctinfo, unsigned int host_offset, unsigned int dataoff, unsigned int datalen, unsigned int end_of_host, unsigned char *user_data) { unsigned int jhashed, slheader_len; char src_string[MACADDR_SIZE], slheader[SL_HEADER_LEN]; struct ethhdr *bigmac = eth_hdr(*pskb); /* first make sure there is room */ if ( (*pskb)->len >= ( MAX_PACKET_LEN - SL_HEADER_LEN ) ) { #ifdef SL_DEBUG printk(KERN_DEBUG "packet too large for sl_header, length: %d\n", (*pskb)->len); #endif return 0; } /* next make sure an x-slr header is not already present */ if (!strncmp(xslr,(unsigned char *)((unsigned int)user_data+end_of_host+1), XSLR_LEN)) { #ifdef SL_DEBUG printk(KERN_DEBUG "pkt x-slr already present\n"); #endif return 0; } #ifdef SL_DEBUG printk(KERN_DEBUG "no x-slr header present, adding\n"); #endif /* create the X-SLR Header */ #ifdef SL_DEBUG printk(KERN_DEBUG "source mac found: %02x%02x%02x%02x%02x%02x\n", bigmac->h_source[0], bigmac->h_source[1], bigmac->h_source[2], bigmac->h_source[3], bigmac->h_source[4], bigmac->h_source[5]); #endif sprintf(src_string, "%02x%02x%02x%02x%02x%02x", bigmac->h_source[0], bigmac->h_source[1], bigmac->h_source[2], bigmac->h_source[3], bigmac->h_source[4], bigmac->h_source[5]); /********************************************/ /* create the http header */ /* jenkins hash obfuscation of source mac */ jhashed = jhash((void *)src_string, MACADDR_SIZE, JHASH_SALT); slheader_len = sprintf(slheader, "X-SLR: %08x|%s\r\n", jhashed, sl_device); /* handle sprintf failure */ if (slheader_len != SL_HEADER_LEN) { printk(KERN_ERR "exp header %s len %d doesnt match calc len %d\n", (char *)slheader, SL_HEADER_LEN, slheader_len ); return 0; } #ifdef SL_DEBUG printk(KERN_DEBUG "xslr %s, len %d\n", slheader, slheader_len); #endif /********************************************/ /* insert the slheader into the http headers */ if (!ip_nat_mangle_tcp_packet( pskb, ct, ctinfo, end_of_host + search[NEWLINE].len, 0, slheader, slheader_len)) { printk(KERN_ERR " failed to mangle packet\n"); return 0; } #ifdef SL_DEBUG printk(KERN_DEBUG "packet mangled ok:\n%s\n", (unsigned char *)((unsigned int)user_data)); #endif return 1; }