From ffa83b5968b534f679bc34acc506801db3d28d58 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Thu, 31 May 2012 10:52:46 +0200 Subject: add mangle functions for IPv4/TCP and IPv4/UDP Signed-off-by: Pablo Neira Ayuso --- src/extra/checksum.c | 1 + src/extra/ipv4.c | 19 ++++++++++++++++ src/extra/ipv6.c | 1 + src/extra/pktbuff.c | 62 ++++++++++++++++++++++++++++++++++++++++++++++++++++ src/extra/tcp.c | 33 ++++++++++++++++++++++++---- src/extra/udp.c | 23 +++++++++++++++++++ src/internal.h | 2 ++ 7 files changed, 137 insertions(+), 4 deletions(-) (limited to 'src') 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 -- cgit v1.2.3