static int map_sip_addr(struct sk_buff **pskb, enum ip_conntrack_info ctinfo, struct nf_conn *ct, const char **dptr, size_t dlen, enum sip_header_pos pos, struct addr_map *map) { enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo); unsigned int matchlen, matchoff, addrlen; char *addr; if (ct_sip_get_info(ct, *dptr, dlen, &matchoff, &matchlen, pos) <= 0) return 1; if ((matchlen == map->addr[dir].srciplen || matchlen == map->addr[dir].srclen) && strncmp(*dptr + matchoff, map->addr[dir].src, matchlen) == 0) { addr = map->addr[!dir].dst; addrlen = map->addr[!dir].dstlen; } else if ((matchlen == map->addr[dir].dstiplen || matchlen == map->addr[dir].dstlen) && strncmp(*dptr + matchoff, map->addr[dir].dst, matchlen) == 0) { addr = map->addr[!dir].src; addrlen = map->addr[!dir].srclen; } else return 1; if (!nf_nat_mangle_udp_packet(pskb, ct, ctinfo, matchoff, matchlen, addr, addrlen)) return 0; *dptr = (*pskb)->data + ip_hdrlen(*pskb) + sizeof(struct udphdr); return 1; }
static unsigned int mangle_packet(struct sk_buff *skb, unsigned int protoff, unsigned int dataoff, const char **dptr, unsigned int *datalen, unsigned int matchoff, unsigned int matchlen, const char *buffer, unsigned int buflen) { enum ip_conntrack_info ctinfo; struct nf_conn *ct = nf_ct_get(skb, &ctinfo); struct tcphdr *th; unsigned int baseoff; if (nf_ct_protonum(ct) == IPPROTO_TCP) { th = (struct tcphdr *)(skb->data + protoff); baseoff = protoff + th->doff * 4; matchoff += dataoff - baseoff; if (!__nf_nat_mangle_tcp_packet(skb, ct, ctinfo, protoff, matchoff, matchlen, buffer, buflen, false)) return 0; } else { baseoff = protoff + sizeof(struct udphdr); matchoff += dataoff - baseoff; if (!nf_nat_mangle_udp_packet(skb, ct, ctinfo, protoff, matchoff, matchlen, buffer, buflen)) return 0; } /* Reload data pointer and adjust datalen value */ *dptr = skb->data + dataoff; *datalen += buflen - matchlen; return 1; }
static int mangle_content_len(struct sk_buff **pskb, enum ip_conntrack_info ctinfo, struct nf_conn *ct, const char *dptr) { unsigned int dataoff, matchoff, matchlen; char buffer[sizeof("65536")]; int bufflen; dataoff = ip_hdrlen(*pskb) + sizeof(struct udphdr); /* Get actual SDP lenght */ if (ct_sip_get_info(ct, dptr, (*pskb)->len - dataoff, &matchoff, &matchlen, POS_SDP_HEADER) > 0) { /* since ct_sip_get_info() give us a pointer passing 'v=' we need to add 2 bytes in this count. */ int c_len = (*pskb)->len - dataoff - matchoff + 2; /* Now, update SDP length */ if (ct_sip_get_info(ct, dptr, (*pskb)->len - dataoff, &matchoff, &matchlen, POS_CONTENT) > 0) { bufflen = sprintf(buffer, "%u", c_len); return nf_nat_mangle_udp_packet(pskb, ct, ctinfo, matchoff, matchlen, buffer, bufflen); } } return 0; }
static int set_addr(struct sk_buff **pskb, unsigned char **data, int dataoff, unsigned int addroff, __be32 ip, __be16 port) { enum ip_conntrack_info ctinfo; struct nf_conn *ct = nf_ct_get(*pskb, &ctinfo); struct { __be32 ip; __be16 port; } __attribute__ ((__packed__)) buf; struct tcphdr _tcph, *th; buf.ip = ip; buf.port = port; addroff += dataoff; if (ip_hdr(*pskb)->protocol == IPPROTO_TCP) { if (!nf_nat_mangle_tcp_packet(pskb, ct, ctinfo, addroff, sizeof(buf), (char *) &buf, sizeof(buf))) { if (net_ratelimit()) printk("nf_nat_h323: nf_nat_mangle_tcp_packet" " error\n"); return -1; } /* Relocate data pointer */ th = skb_header_pointer(*pskb, ip_hdrlen(*pskb), sizeof(_tcph), &_tcph); if (th == NULL) return -1; *data = (*pskb)->data + ip_hdrlen(*pskb) + th->doff * 4 + dataoff; } else { if (!nf_nat_mangle_udp_packet(pskb, ct, ctinfo, addroff, sizeof(buf), (char *) &buf, sizeof(buf))) { if (net_ratelimit()) printk("nf_nat_h323: nf_nat_mangle_udp_packet" " error\n"); return -1; } /* nf_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 + ip_hdrlen(*pskb) + sizeof(struct udphdr)); } return 0; }
static unsigned int mangle_packet(struct sk_buff *skb, const char **dptr, unsigned int *datalen, unsigned int matchoff, unsigned int matchlen, const char *buffer, unsigned int buflen) { enum ip_conntrack_info ctinfo; struct nf_conn *ct = nf_ct_get(skb, &ctinfo); if (!nf_nat_mangle_udp_packet(skb, ct, ctinfo, matchoff, matchlen, buffer, buflen)) return 0; /* Reload data pointer and adjust datalen value */ *dptr = skb->data + ip_hdrlen(skb) + sizeof(struct udphdr); *datalen += buflen - matchlen; return 1; }
static unsigned int help(struct sk_buff *skb, enum ip_conntrack_info ctinfo, unsigned int matchoff, unsigned int matchlen, struct nf_conntrack_expect *exp) { char buffer[sizeof("65535")]; u_int16_t port; unsigned int ret; /* Connection comes from client. */ exp->saved_proto.tcp.port = exp->tuple.dst.u.tcp.port; exp->dir = IP_CT_DIR_ORIGINAL; /* When you see the packet, we need to NAT it the same as the * this one (ie. same IP: it will be TCP and master is UDP). */ exp->expectfn = nf_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++) { int ret; exp->tuple.dst.u.tcp.port = htons(port); ret = nf_ct_expect_related(exp); if (ret == 0) break; else if (ret != -EBUSY) { port = 0; break; } } if (port == 0) return NF_DROP; sprintf(buffer, "%u", port); ret = nf_nat_mangle_udp_packet(skb, exp->master, ctinfo, matchoff, matchlen, buffer, strlen(buffer)); if (ret != NF_ACCEPT) nf_ct_unexpect_related(exp); return ret; }
static unsigned int mangle_sip_packet(struct sk_buff **pskb, enum ip_conntrack_info ctinfo, struct nf_conn *ct, const char **dptr, size_t dlen, char *buffer, int bufflen, enum sip_header_pos pos) { unsigned int matchlen, matchoff; if (ct_sip_get_info(ct, *dptr, dlen, &matchoff, &matchlen, pos) <= 0) return 0; if (!nf_nat_mangle_udp_packet(pskb, ct, ctinfo, matchoff, matchlen, buffer, bufflen)) return 0; /* We need to reload this. Thanks Patrick. */ *dptr = (*pskb)->data + ip_hdrlen(*pskb) + sizeof(struct udphdr); return 1; }