summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorPablo Neira Ayuso <pablo@netfilter.org>2012-05-31 10:52:46 +0200
committerPablo Neira Ayuso <pablo@netfilter.org>2012-08-06 14:54:27 +0200
commitffa83b5968b534f679bc34acc506801db3d28d58 (patch)
treeced3718e02b9e43e3174c55146bf967e9bd5ffce /src
parentf40eabb01163f383e2471942da45f32361031e39 (diff)
add mangle functions for IPv4/TCP and IPv4/UDP
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
Diffstat (limited to 'src')
-rw-r--r--src/extra/checksum.c1
-rw-r--r--src/extra/ipv4.c19
-rw-r--r--src/extra/ipv6.c1
-rw-r--r--src/extra/pktbuff.c62
-rw-r--r--src/extra/tcp.c33
-rw-r--r--src/extra/udp.c23
-rw-r--r--src/internal.h2
7 files changed, 137 insertions, 4 deletions
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 <stdio.h>
+#include <stdbool.h>
#include <arpa/inet.h>
#include <netinet/ip.h>
#include <netinet/ip6.h>
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 <stdio.h>
+#include <stdbool.h>
#include <arpa/inet.h>
#include <netinet/ip.h>
@@ -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 <stdio.h>
#include <stddef.h>
+#include <stdbool.h>
#include <arpa/inet.h>
#include <netinet/ip6.h>
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 <stdlib.h>
#include <string.h> /* for memcpy */
+#include <stdbool.h>
#include <netinet/if_ether.h>
#include <netinet/ip.h>
@@ -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 <stdio.h>
#include <string.h> /* for memcpy */
+#include <stdbool.h>
#include <arpa/inet.h>
#include <netinet/ip.h>
#include <netinet/ip6.h>
@@ -18,6 +19,7 @@
#include <libnetfilter_queue/libnetfilter_queue.h>
#include <libnetfilter_queue/libnetfilter_queue_tcp.h>
+#include <libnetfilter_queue/libnetfilter_queue_ipv4.h>
#include <libnetfilter_queue/pktbuff.h>
#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 <stdio.h>
+#include <stdbool.h>
#include <arpa/inet.h>
#include <netinet/ip.h>
#include <netinet/ip6.h>
@@ -17,6 +18,7 @@
#include <libnetfilter_queue/libnetfilter_queue.h>
#include <libnetfilter_queue/libnetfilter_queue_udp.h>
+#include <libnetfilter_queue/libnetfilter_queue_ipv4.h>
#include <libnetfilter_queue/pktbuff.h>
#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