From: Pablo Neira Ayuso Date: Thu, 31 May 2012 08:52:46 +0000 (+0200) Subject: add mangle functions for IPv4/TCP and IPv4/UDP X-Git-Tag: upstream/1.0.2~34 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=8f4248f2945345460f80a430876d892efd8cdd2d;p=platform%2Fupstream%2Flibnetfilter_queue.git add mangle functions for IPv4/TCP and IPv4/UDP Signed-off-by: Pablo Neira Ayuso --- diff --git a/include/libnetfilter_queue/libnetfilter_queue_ipv4.h b/include/libnetfilter_queue/libnetfilter_queue_ipv4.h index d18924e..e707f1f 100644 --- a/include/libnetfilter_queue/libnetfilter_queue_ipv4.h +++ b/include/libnetfilter_queue/libnetfilter_queue_ipv4.h @@ -7,6 +7,7 @@ struct iphdr; struct iphdr *nfq_ip_get_hdr(struct pkt_buff *pktb); int nfq_ip_set_transport_header(struct pkt_buff *pktb, struct iphdr *iph); void nfq_ip_set_checksum(struct iphdr *iph); +int nfq_ip_mangle(struct pkt_buff *pkt, unsigned int dataoff, unsigned int match_offset, unsigned int match_len, const char *rep_buffer, unsigned int rep_len); int nfq_ip_snprintf(char *buf, size_t size, const struct iphdr *iph); #endif diff --git a/include/libnetfilter_queue/libnetfilter_queue_tcp.h b/include/libnetfilter_queue/libnetfilter_queue_tcp.h index cc965f5..c66dfb6 100644 --- a/include/libnetfilter_queue/libnetfilter_queue_tcp.h +++ b/include/libnetfilter_queue/libnetfilter_queue_tcp.h @@ -13,6 +13,8 @@ struct ip6_hdr; void nfq_tcp_compute_checksum_ipv4(struct tcphdr *tcph, struct iphdr *iph); void nfq_tcp_compute_checksum_ipv6(struct tcphdr *tcph, struct ip6_hdr *ip6h); +int nfq_tcp_mangle_ipv4(struct pkt_buff *pkt, unsigned int match_offset, unsigned int match_len, const char *rep_buffer, unsigned int rep_len); + int nfq_tcp_snprintf(char *buf, size_t size, const struct tcphdr *tcp); #endif diff --git a/include/libnetfilter_queue/libnetfilter_queue_udp.h b/include/libnetfilter_queue/libnetfilter_queue_udp.h index e1aeb73..f4b6c49 100644 --- a/include/libnetfilter_queue/libnetfilter_queue_udp.h +++ b/include/libnetfilter_queue/libnetfilter_queue_udp.h @@ -10,6 +10,8 @@ unsigned int nfq_udp_get_payload_len(struct udphdr *udph, struct pkt_buff *pktb) void nfq_udp_compute_checksum_ipv4(struct udphdr *udph, struct iphdr *iph); void nfq_udp_compute_checksum_ipv6(struct udphdr *udph, struct ip6_hdr *ip6h); +int nfq_udp_mangle_ipv4(struct pkt_buff *pkt, unsigned int match_offset, unsigned int match_len, const char *rep_buffer, unsigned int rep_len); + int nfq_udp_snprintf(char *buf, size_t size, const struct udphdr *udp); #endif diff --git a/include/libnetfilter_queue/pktbuff.h b/include/libnetfilter_queue/pktbuff.h index a0e7abf..b15ee1e 100644 --- a/include/libnetfilter_queue/pktbuff.h +++ b/include/libnetfilter_queue/pktbuff.h @@ -19,4 +19,8 @@ uint8_t *pktb_mac_header(struct pkt_buff *pktb); uint8_t *pktb_network_header(struct pkt_buff *pktb); uint8_t *pktb_transport_header(struct pkt_buff *pktb); +int pktb_mangle(struct pkt_buff *pkt, unsigned int dataoff, unsigned int match_offset, unsigned int match_len, const char *rep_buffer, unsigned int rep_len); + +bool pktb_mangled(const struct pkt_buff *pktb); + #endif diff --git a/src/extra/checksum.c b/src/extra/checksum.c index d0c4167..6f07e71 100644 --- a/src/extra/checksum.c +++ b/src/extra/checksum.c @@ -10,6 +10,7 @@ */ #include +#include #include #include #include diff --git a/src/extra/ipv4.c b/src/extra/ipv4.c index 200a20e..ce101ef 100644 --- a/src/extra/ipv4.c +++ b/src/extra/ipv4.c @@ -10,6 +10,7 @@ */ #include +#include #include #include @@ -90,6 +91,24 @@ void nfq_ip_set_checksum(struct iphdr *iph) } EXPORT_SYMBOL(nfq_ip_set_checksum); +int nfq_ip_mangle(struct pkt_buff *pkt, unsigned int dataoff, + unsigned int match_offset, unsigned int match_len, + const char *rep_buffer, unsigned int rep_len) +{ + struct iphdr *iph = (struct iphdr *) pkt->network_header; + + if (!pktb_mangle(pkt, dataoff, match_offset, match_len, + rep_buffer, rep_len)) + return 0; + + /* fix IP hdr checksum information */ + iph->tot_len = htons(pkt->len); + nfq_ip_set_checksum(iph); + + return 1; +} +EXPORT_SYMBOL(nfq_ip_mangle); + /** * nfq_pkt_snprintf_ip - print IPv4 header into buffer in iptables LOG format * \param buf: pointer to buffer that will be used to print the header diff --git a/src/extra/ipv6.c b/src/extra/ipv6.c index 0457016..7c5dc9b 100644 --- a/src/extra/ipv6.c +++ b/src/extra/ipv6.c @@ -11,6 +11,7 @@ #include #include +#include #include #include diff --git a/src/extra/pktbuff.c b/src/extra/pktbuff.c index 809953b..e9ca5da 100644 --- a/src/extra/pktbuff.c +++ b/src/extra/pktbuff.c @@ -11,6 +11,7 @@ #include #include /* for memcpy */ +#include #include #include @@ -137,6 +138,67 @@ uint8_t *pktb_transport_header(struct pkt_buff *pktb) return pktb->transport_header; } +static int pktb_expand_tail(struct pkt_buff *pkt, int extra) +{ + /* XXX: support reallocation case. */ + pkt->len += extra; + pkt->tail = pkt->tail + extra; + return 0; +} + +static int enlarge_pkt(struct pkt_buff *pkt, unsigned int extra) +{ + if (pkt->len + extra > 65535) + return 0; + + if (pktb_expand_tail(pkt, extra - pktb_tailroom(pkt))) + return 0; + + return 1; +} + +int pktb_mangle(struct pkt_buff *pkt, + unsigned int dataoff, + unsigned int match_offset, + unsigned int match_len, + const char *rep_buffer, + unsigned int rep_len) +{ + unsigned char *data; + + if (rep_len > match_len && + rep_len - match_len > pktb_tailroom(pkt) && + !enlarge_pkt(pkt, rep_len - match_len)) + return 0; + + data = pkt->network_header + dataoff; + + /* move post-replacement */ + memmove(data + match_offset + rep_len, + data + match_offset + match_len, + pkt->tail - (pkt->network_header + dataoff + + match_offset + match_len)); + + /* insert data from buffer */ + memcpy(data + match_offset, rep_buffer, rep_len); + + /* update pkt info */ + if (rep_len > match_len) + pktb_put(pkt, rep_len - match_len); + else + pktb_trim(pkt, pkt->len + rep_len - match_len); + + pkt->mangled = true; + return 1; +} +EXPORT_SYMBOL(pktb_mangle); + +bool pktb_mangled(const struct pkt_buff *pkt) +{ + return pkt->mangled; +} +EXPORT_SYMBOL(pktb_mangled); + /** * @} */ diff --git a/src/extra/tcp.c b/src/extra/tcp.c index 9de3748..2ea0d8a 100644 --- a/src/extra/tcp.c +++ b/src/extra/tcp.c @@ -11,6 +11,7 @@ #include #include /* for memcpy */ +#include #include #include #include @@ -18,6 +19,7 @@ #include #include +#include #include #include "internal.h" @@ -134,12 +136,12 @@ int nfq_tcp_snprintf(char *buf, size_t size, const struct tcphdr *tcph) #define TCP_RESERVED_BITS htonl(0x0F000000) ret = snprintf(buf, size, "SPT=%u DPT=%u SEQ=%u ACK=%u " - "WINDOW=%u RES=%0x%02x ", + "WINDOW=%u RES=0x%02x ", ntohs(tcph->source), ntohs(tcph->dest), ntohl(tcph->seq), ntohl(tcph->ack_seq), ntohs(tcph->window), - (uint8_t)(ntohl(tcp_flag_word(tcph) & - TCP_RESERVED_BITS) >> 22)); + (uint8_t) + (ntohl(tcp_flag_word(tcph) & TCP_RESERVED_BITS) >> 22)); len += ret; if (tcph->urg) { @@ -166,10 +168,33 @@ int nfq_tcp_snprintf(char *buf, size_t size, const struct tcphdr *tcph) ret = snprintf(buf+len, size-len, "FIN "); len += ret; } - /* Not TCP options implemented yet, sorry. */ + /* XXX: Not TCP options implemented yet, sorry. */ + + return ret; } EXPORT_SYMBOL(nfq_tcp_snprintf); +int +nfq_tcp_mangle_ipv4(struct pkt_buff *pkt, + unsigned int match_offset, unsigned int match_len, + const char *rep_buffer, unsigned int rep_len) +{ + struct iphdr *iph; + struct tcphdr *tcph; + + iph = (struct iphdr *)pkt->network_header; + tcph = (struct tcphdr *)(pkt->network_header + iph->ihl*4); + + if (!nfq_ip_mangle(pkt, iph->ihl*4 + tcph->doff*4, + match_offset, match_len, rep_buffer, rep_len)) + return 0; + + nfq_tcp_compute_checksum_ipv4(tcph, iph); + + return 1; +} +EXPORT_SYMBOL(nfq_tcp_mangle_ipv4); + /** * @} */ diff --git a/src/extra/udp.c b/src/extra/udp.c index c0b1b7d..5f7f9ec 100644 --- a/src/extra/udp.c +++ b/src/extra/udp.c @@ -10,6 +10,7 @@ */ #include +#include #include #include #include @@ -17,6 +18,7 @@ #include #include +#include #include #include "internal.h" @@ -112,6 +114,27 @@ nfq_udp_compute_checksum_ipv6(struct udphdr *udph, struct ip6_hdr *ip6h) } EXPORT_SYMBOL(nfq_udp_compute_checksum_ipv6); +int +nfq_udp_mangle_ipv4(struct pkt_buff *pkt, + unsigned int match_offset, unsigned int match_len, + const char *rep_buffer, unsigned int rep_len) +{ + struct iphdr *iph; + struct udphdr *udph; + + iph = (struct iphdr *)pkt->network_header; + udph = (struct udphdr *)(pkt->network_header + iph->ihl*4); + + if (!nfq_ip_mangle(pkt, iph->ihl*4 + sizeof(struct udphdr), + match_offset, match_len, rep_buffer, rep_len)) + return 0; + + nfq_udp_compute_checksum_ipv4(udph, iph); + + return 1; +} +EXPORT_SYMBOL(nfq_udp_mangle_ipv4); + /** * nfq_pkt_snprintf_udp_hdr - print udp header into one buffer in a humnan * readable way diff --git a/src/internal.h b/src/internal.h index 477dc70..37bf79e 100644 --- a/src/internal.h +++ b/src/internal.h @@ -27,6 +27,8 @@ struct pkt_buff { uint32_t len; uint32_t data_len; + + bool mangled; }; #endif