summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/extra/checksum.c14
-rw-r--r--src/extra/ipv4.c56
-rw-r--r--src/extra/ipv6.c35
-rw-r--r--src/extra/pktbuff.c36
-rw-r--r--src/extra/tcp.c108
-rw-r--r--src/extra/udp.c111
-rw-r--r--src/internal.h6
-rw-r--r--src/libnetfilter_queue.c62
-rw-r--r--src/nlmsg.c41
9 files changed, 332 insertions, 137 deletions
diff --git a/src/extra/checksum.c b/src/extra/checksum.c
index 42389aa..a650b64 100644
--- a/src/extra/checksum.c
+++ b/src/extra/checksum.c
@@ -62,21 +62,21 @@ uint16_t nfq_checksum_tcpudp_ipv6(struct ip6_hdr *ip6h, void *transport_hdr,
uint16_t protonum)
{
uint32_t sum = 0;
- uint32_t hdr_len = (uint32_t *)transport_hdr - (uint32_t *)ip6h;
- uint32_t len = ip6h->ip6_plen - hdr_len;
+ uint32_t hdr_len = (uint8_t *)transport_hdr - (uint8_t *)ip6h;
+ /* Allow for extra headers before the UDP header */
+ /* TODO: Deal with routing headers */
+ uint32_t len = ntohs(ip6h->ip6_plen) - (hdr_len - sizeof *ip6h);
uint8_t *payload = (uint8_t *)ip6h + hdr_len;
int i;
for (i=0; i<8; i++) {
- sum += (ip6h->ip6_src.s6_addr16[i] >> 16) & 0xFFFF;
- sum += (ip6h->ip6_src.s6_addr16[i]) & 0xFFFF;
+ sum += (ip6h->ip6_src.s6_addr16[i]);
}
for (i=0; i<8; i++) {
- sum += (ip6h->ip6_dst.s6_addr16[i] >> 16) & 0xFFFF;
- sum += (ip6h->ip6_dst.s6_addr16[i]) & 0xFFFF;
+ sum += (ip6h->ip6_dst.s6_addr16[i]);
}
sum += htons(protonum);
- sum += htons(ip6h->ip6_plen);
+ sum += htons(len);
return nfq_checksum(sum, (uint16_t *)payload, len);
}
diff --git a/src/extra/ipv4.c b/src/extra/ipv4.c
index c03f23f..797bab1 100644
--- a/src/extra/ipv4.c
+++ b/src/extra/ipv4.c
@@ -26,17 +26,21 @@
*/
/**
- * nfq_ip_get_hdr - get IPv4 header
+ * nfq_ip_get_hdr - get the IPv4 header
* \param pktb: Pointer to user-space network packet buffer
+ * \returns validated pointer to the IPv4 header or NULL if IP is malformed or
+ * not version 4
*
- * This funcion returns NULL if the IPv4 is malformed or the protocol version
- * is not 4. On success, it returns a valid pointer to the IPv4 header.
+ * Many programs will not need to call this function. A possible use is to
+ * determine the layer 4 protocol. The validation is that the buffer is big
+ * enough for the declared lengths in the header, i.e. an extra check for packet
+ * truncation.
*/
EXPORT_SYMBOL
struct iphdr *nfq_ip_get_hdr(struct pkt_buff *pktb)
{
struct iphdr *iph;
- unsigned int pktlen = pktb->tail - pktb->network_header;
+ unsigned int pktlen = pktb_tail(pktb) - pktb->network_header;
/* Not enough room for IPv4 header. */
if (pktlen < sizeof(struct iphdr))
@@ -56,13 +60,14 @@ struct iphdr *nfq_ip_get_hdr(struct pkt_buff *pktb)
}
/**
- * nfq_ip_set_transport_header - set transport header
+ * nfq_ip_set_transport_header - set the \b transport_header field in \b pktb
* \param pktb: Pointer to user-space network packet buffer
* \param iph: Pointer to the IPv4 header
- *
- * Sets the \b transport_header field in \b pktb
- *
- * Level 4 helper functions need this to be set.
+ * \returns 0 on success or -1 if a minimal validation check fails
+ * \note
+ * Most programs should call __nfq_ip_set_transport_header__ as soon as
+ * possible, since most layer 4 helper functions assume the
+ * \b transport_header field is valid.
*/
EXPORT_SYMBOL
int nfq_ip_set_transport_header(struct pkt_buff *pktb, struct iphdr *iph)
@@ -78,11 +83,20 @@ int nfq_ip_set_transport_header(struct pkt_buff *pktb, struct iphdr *iph)
}
/**
+ * \defgroup ip_internals Internal IP functions
+ *
+ * Most user-space programs will never need these.
+ *
+ * @{
+ */
+
+/**
* nfq_ip_set_checksum - set IPv4 checksum
* \param iph: Pointer to the IPv4 header
- *
- * \note Call to this function if you modified the IPv4 header to update the
- * checksum.
+ * \note
+ * nfq_ip_mangle() invokes this function.
+ * As long as developers always use the appropriate mangler for the layer being
+ * mangled, there is no need to call __nfq_ip_set_checksum__.
*/
EXPORT_SYMBOL
void nfq_ip_set_checksum(struct iphdr *iph)
@@ -94,16 +108,20 @@ void nfq_ip_set_checksum(struct iphdr *iph)
}
/**
+ * @}
+ */
+
+/**
* nfq_ip_mangle - mangle IPv4 packet buffer
* \param pktb: Pointer to user-space network packet buffer
- * \param dataoff: Offset to layer 4 header
+ * \param dataoff: Offset to layer 4 header, or zero to mangle IP header
* \param match_offset: Offset to content that you want to mangle
* \param match_len: Length of the existing content you want to mangle
* \param rep_buffer: Pointer to data you want to use to replace current content
* \param rep_len: Length of data you want to use to replace current content
* \returns 1 for success and 0 for failure. See pktb_mangle() for failure case
- * \note This function updates the IPv4 length and recalculates the IPv4
- * checksum (if necessary)
+ * \note This function updates the IPv4 length if necessary and recalculates the
+ * IPv4 checksum.
*/
EXPORT_SYMBOL
int nfq_ip_mangle(struct pkt_buff *pktb, unsigned int dataoff,
@@ -117,7 +135,7 @@ int nfq_ip_mangle(struct pkt_buff *pktb, unsigned int dataoff,
return 0;
/* fix IP hdr checksum information */
- iph->tot_len = htons(pktb->tail - pktb->network_header);
+ iph->tot_len = htons(pktb_tail(pktb) - pktb->network_header);
nfq_ip_set_checksum(iph);
return 1;
@@ -128,10 +146,8 @@ int nfq_ip_mangle(struct pkt_buff *pktb, unsigned int dataoff,
* \param buf: Pointer to buffer that will be used to print the header
* \param size: Size of the buffer (or remaining room in it)
* \param iph: Pointer to a valid IPv4 header
- *
- * This function returns the number of bytes written (excluding the
- * string-terminating NUL) *assuming sufficient room in the buffer*.
- * Read the snprintf manpage for more information about this strange behaviour.
+ * \returns same as snprintf
+ * \sa **snprintf**(3)
*/
EXPORT_SYMBOL
int nfq_ip_snprintf(char *buf, size_t size, const struct iphdr *iph)
diff --git a/src/extra/ipv6.c b/src/extra/ipv6.c
index f685b3b..42c5e25 100644
--- a/src/extra/ipv6.c
+++ b/src/extra/ipv6.c
@@ -36,7 +36,7 @@ EXPORT_SYMBOL
struct ip6_hdr *nfq_ip6_get_hdr(struct pkt_buff *pktb)
{
struct ip6_hdr *ip6h;
- unsigned int pktlen = pktb->tail - pktb->network_header;
+ unsigned int pktlen = pktb_tail(pktb) - pktb->network_header;
/* Not enough room for IPv6 header. */
if (pktlen < sizeof(struct ip6_hdr))
@@ -77,7 +77,7 @@ int nfq_ip6_set_transport_header(struct pkt_buff *pktb, struct ip6_hdr *ip6h,
break;
}
/* No room for extension, bad packet. */
- if (pktb->tail - cur < sizeof(struct ip6_ext)) {
+ if (pktb_tail(pktb) - cur < sizeof(struct ip6_ext)) {
cur = NULL;
break;
}
@@ -87,7 +87,7 @@ int nfq_ip6_set_transport_header(struct pkt_buff *pktb, struct ip6_hdr *ip6h,
uint16_t *frag_off;
/* No room for full fragment header, bad packet. */
- if (pktb->tail - cur < sizeof(struct ip6_frag)) {
+ if (pktb_tail(pktb) - cur < sizeof(struct ip6_frag)) {
cur = NULL;
break;
}
@@ -117,6 +117,35 @@ int nfq_ip6_set_transport_header(struct pkt_buff *pktb, struct ip6_hdr *ip6h,
}
/**
+ * nfq_ip6_mangle - mangle IPv6 packet buffer
+ * \param pktb: Pointer to user-space network packet buffer
+ * \param dataoff: Offset to layer 4 header
+ * \param match_offset: Offset to content that you want to mangle
+ * \param match_len: Length of the existing content you want to mangle
+ * \param rep_buffer: Pointer to data you want to use to replace current content
+ * \param rep_len: Length of data you want to use to replace current content
+ * \returns 1 for success and 0 for failure. See pktb_mangle() for failure case
+ * \note This function updates the IPv6 length (if necessary)
+ */
+EXPORT_SYMBOL
+int nfq_ip6_mangle(struct pkt_buff *pktb, unsigned int dataoff,
+ unsigned int match_offset, unsigned int match_len,
+ const char *rep_buffer, unsigned int rep_len)
+{
+ struct ip6_hdr *ip6h = (struct ip6_hdr *)pktb->network_header;
+
+ if (!pktb_mangle(pktb, dataoff, match_offset, match_len, rep_buffer,
+ rep_len))
+ return 0;
+
+ /* Fix IPv6 hdr length information */
+ ip6h->ip6_plen =
+ htons(pktb_tail(pktb) - pktb->network_header - sizeof *ip6h);
+
+ return 1;
+}
+
+/**
* nfq_ip6_snprintf - print IPv6 header into one buffer in iptables LOG format
* \param buf: Pointer to buffer that is used to print the object
* \param size: Size of the buffer (or remaining room in it).
diff --git a/src/extra/pktbuff.c b/src/extra/pktbuff.c
index 26d7ca8..6dd0ca9 100644
--- a/src/extra/pktbuff.c
+++ b/src/extra/pktbuff.c
@@ -52,6 +52,7 @@ EXPORT_SYMBOL
struct pkt_buff *pktb_alloc(int family, void *data, size_t len, size_t extra)
{
struct pkt_buff *pktb;
+ struct ethhdr *ethhdr;
void *pkt_data;
pktb = calloc(1, sizeof(struct pkt_buff) + len + extra);
@@ -65,18 +66,15 @@ struct pkt_buff *pktb_alloc(int family, void *data, size_t len, size_t extra)
pktb->len = len;
pktb->data_len = len + extra;
- pktb->head = pkt_data;
pktb->data = pkt_data;
- pktb->tail = pktb->head + len;
switch(family) {
case AF_INET:
case AF_INET6:
pktb->network_header = pktb->data;
break;
- case AF_BRIDGE: {
- struct ethhdr *ethhdr = (struct ethhdr *)pktb->data;
-
+ case AF_BRIDGE:
+ ethhdr = (struct ethhdr *)pktb->data;
pktb->mac_header = pktb->data;
switch(ethhdr->h_proto) {
@@ -92,7 +90,6 @@ struct pkt_buff *pktb_alloc(int family, void *data, size_t len, size_t extra)
}
break;
}
- }
return pktb;
}
@@ -111,7 +108,7 @@ uint8_t *pktb_data(struct pkt_buff *pktb)
}
/**
- * pktb_len - return length of the packet buffer
+ * pktb_len - get length of packet buffer
* \param pktb Pointer to userspace packet buffer
* \return Length of packet contained within __pktb__
* \par
@@ -192,7 +189,6 @@ void pktb_pull(struct pkt_buff *pktb, unsigned int len)
EXPORT_SYMBOL
void pktb_put(struct pkt_buff *pktb, unsigned int len)
{
- pktb->tail += len;
pktb->len += len;
}
@@ -205,7 +201,6 @@ EXPORT_SYMBOL
void pktb_trim(struct pkt_buff *pktb, unsigned int len)
{
pktb->len = len;
- pktb->tail = pktb->head + len;
}
/**
@@ -271,26 +266,25 @@ uint8_t *pktb_transport_header(struct pkt_buff *pktb)
* @}
*/
-static int pktb_expand_tail(struct pkt_buff *pkt, int extra)
+static int pktb_expand_tail(struct pkt_buff *pktb, int extra)
{
/* No room in packet, cannot mangle it. We don't support dynamic
* reallocation. Instead, increase the size of the extra room in
* the tail in pktb_alloc.
*/
- if (pkt->len + extra > pkt->data_len)
+ if (pktb->len + extra > pktb->data_len)
return 0;
- pkt->len += extra;
- pkt->tail = pkt->tail + extra;
+ pktb->len += extra;
return 1;
}
-static int enlarge_pkt(struct pkt_buff *pkt, unsigned int extra)
+static int enlarge_pkt(struct pkt_buff *pktb, unsigned int extra)
{
- if (pkt->len + extra > 65535)
+ if (pktb->len + extra > 65535)
return 0;
- if (!pktb_expand_tail(pkt, extra - pktb_tailroom(pkt)))
+ if (!pktb_expand_tail(pktb, extra - pktb_tailroom(pktb)))
return 0;
return 1;
@@ -299,8 +293,10 @@ static int enlarge_pkt(struct pkt_buff *pkt, unsigned int extra)
/**
* pktb_mangle - adjust contents of a packet
* \param pktb Pointer to userspace packet buffer
- * \param dataoff Offset to layer 4 header. Specify zero to access layer 3 (IP)
- * header (layer 2 for family \b AF_BRIDGE)
+ * \param dataoff Supplementary offset, usually offset from layer 3 (IP) header
+ * to the layer 4 (TCP or UDP) header. Specify zero to access the layer 3
+ * header. If \b pktb was created in family \b AF_BRIDGE, specify
+ * \b -ETH_HLEN (a negative offset) to access the layer 2 (MAC) header.
* \param match_offset Further offset to content that you want to mangle
* \param match_len Length of the existing content you want to mangle
* \param rep_buffer Pointer to data you want to use to replace current content
@@ -316,7 +312,7 @@ static int enlarge_pkt(struct pkt_buff *pkt, unsigned int extra)
*/
EXPORT_SYMBOL
int pktb_mangle(struct pkt_buff *pktb,
- unsigned int dataoff,
+ int dataoff,
unsigned int match_offset,
unsigned int match_len,
const char *rep_buffer,
@@ -334,7 +330,7 @@ int pktb_mangle(struct pkt_buff *pktb,
/* move post-replacement */
memmove(data + match_offset + rep_len,
data + match_offset + match_len,
- pktb->tail - (pktb->network_header + dataoff +
+ pktb_tail(pktb) - (pktb->network_header + dataoff +
match_offset + match_len));
/* insert data from buffer */
diff --git a/src/extra/tcp.c b/src/extra/tcp.c
index 136d7ea..933c6ee 100644
--- a/src/extra/tcp.c
+++ b/src/extra/tcp.c
@@ -21,6 +21,7 @@
#include <libnetfilter_queue/libnetfilter_queue.h>
#include <libnetfilter_queue/libnetfilter_queue_tcp.h>
#include <libnetfilter_queue/libnetfilter_queue_ipv4.h>
+#include <libnetfilter_queue/libnetfilter_queue_ipv6.h>
#include <libnetfilter_queue/pktbuff.h>
#include "internal.h"
@@ -31,14 +32,12 @@
*/
/**
- * nfq_tcp_get - get the TCP header
+ * nfq_tcp_get_hdr - get the TCP header
* \param pktb: pointer to user-space network packet buffer
- *
- * This function returns NULL if an invalid TCP header is found. On success,
- * it returns the TCP header.
- *
- * \note You have to call nfq_ip_set_transport_header or
- * nfq_ip6_set_transport_header first to access the TCP header.
+ * \returns validated pointer to the TCP header or NULL if the TCP header was
+ * not set or if a minimal length check fails.
+ * \note You have to call nfq_ip_set_transport_header() or
+ * nfq_ip6_set_transport_header() first to set the TCP header.
*/
EXPORT_SYMBOL
struct tcphdr *nfq_tcp_get_hdr(struct pkt_buff *pktb)
@@ -47,7 +46,7 @@ struct tcphdr *nfq_tcp_get_hdr(struct pkt_buff *pktb)
return NULL;
/* No room for the TCP header. */
- if (pktb->tail - pktb->transport_header < sizeof(struct tcphdr))
+ if (pktb_tail(pktb) - pktb->transport_header < sizeof(struct tcphdr))
return NULL;
return (struct tcphdr *)pktb->transport_header;
@@ -57,6 +56,7 @@ struct tcphdr *nfq_tcp_get_hdr(struct pkt_buff *pktb)
* nfq_tcp_get_payload - get the TCP packet payload
* \param tcph: pointer to the TCP header
* \param pktb: pointer to user-space network packet buffer
+ * \returns Pointer to the TCP payload, or NULL if malformed TCP packet.
*/
EXPORT_SYMBOL
void *nfq_tcp_get_payload(struct tcphdr *tcph, struct pkt_buff *pktb)
@@ -68,7 +68,7 @@ void *nfq_tcp_get_payload(struct tcphdr *tcph, struct pkt_buff *pktb)
return NULL;
/* malformed TCP data offset. */
- if (pktb->transport_header + len > pktb->tail)
+ if (pktb->transport_header + len > pktb_tail(pktb))
return NULL;
return pktb->transport_header + len;
@@ -78,17 +78,31 @@ void *nfq_tcp_get_payload(struct tcphdr *tcph, struct pkt_buff *pktb)
* nfq_tcp_get_payload_len - get the tcp packet payload
* \param tcph: pointer to the TCP header
* \param pktb: pointer to user-space network packet buffer
+ * \returns Length of TCP payload (user data)
*/
EXPORT_SYMBOL
unsigned int nfq_tcp_get_payload_len(struct tcphdr *tcph, struct pkt_buff *pktb)
{
- return pktb->tail - pktb->transport_header;
+ return pktb_tail(pktb) - pktb->transport_header - (tcph->doff * 4);
}
/**
- * nfq_tcp_set_checksum_ipv4 - computes IPv4/TCP packet checksum
+ * \defgroup tcp_internals Internal TCP functions
+ *
+ * Most user-space programs will never need these.
+ *
+ * @{
+ */
+
+/**
+ * nfq_tcp_compute_checksum_ipv4 - computes IPv4/TCP packet checksum
* \param tcph: pointer to the TCP header
* \param iph: pointer to the IPv4 header
+ * \note
+ * nfq_tcp_mangle_ipv4() invokes this function.
+ * As long as developers always use __nfq_tcp_mangle_ipv4__ when changing the
+ * content of a TCP message, there is no need to call
+ * __nfq_tcp_compute_checksum_ipv4__.
*/
EXPORT_SYMBOL
void nfq_tcp_compute_checksum_ipv4(struct tcphdr *tcph, struct iphdr *iph)
@@ -99,9 +113,14 @@ void nfq_tcp_compute_checksum_ipv4(struct tcphdr *tcph, struct iphdr *iph)
}
/**
- * nfq_tcp_set_checksum_ipv6 - computes IPv6/TCP packet checksum
+ * nfq_tcp_compute_checksum_ipv6 - computes IPv6/TCP packet checksum
* \param tcph: pointer to the TCP header
- * \param iph: pointer to the IPv6 header
+ * \param ip6h: pointer to the IPv6 header
+ * \note
+ * nfq_tcp_mangle_ipv6() invokes this function.
+ * As long as developers always use __nfq_tcp_mangle_ipv6__ when changing the
+ * content of a TCP message, there is no need to call
+ * __nfq_tcp_compute_checksum_ipv6__.
*/
EXPORT_SYMBOL
void nfq_tcp_compute_checksum_ipv6(struct tcphdr *tcph, struct ip6_hdr *ip6h)
@@ -111,6 +130,10 @@ void nfq_tcp_compute_checksum_ipv6(struct tcphdr *tcph, struct ip6_hdr *ip6h)
tcph->check = nfq_checksum_tcpudp_ipv6(ip6h, tcph, IPPROTO_TCP);
}
+/**
+ * @}
+ */
+
/*
* The union cast uses a gcc extension to avoid aliasing problems
* (union is compatible to any of its members)
@@ -128,7 +151,9 @@ union tcp_word_hdr {
* readable way
* \param buf: pointer to buffer that is used to print the object
* \param size: size of the buffer (or remaining room in it).
- * \param tcp: pointer to a valid tcp header.
+ * \param tcph: pointer to a valid tcp header.
+ * \returns Same as \b snprintf
+ * \sa __snprintf__(3)
*
*/
EXPORT_SYMBOL
@@ -183,21 +208,25 @@ int nfq_tcp_snprintf(char *buf, size_t size, const struct tcphdr *tcph)
* \param match_len: length of the existing content you want to mangle
* \param rep_buffer: pointer to data you want to use to replace current content
* \param rep_len: length of data you want to use to replace current content
- *
- * \note This function recalculates the IPv4 and TCP checksums for you.
+ * \returns 1 for success and 0 for failure. See pktb_mangle() for failure case
+ * \note This function updates the IPv4 length and recalculates the IPv4 & TCP
+ * checksums for you.
+ * \warning After changing the length of a TCP message, the application will
+ * need to mangle sequence numbers in both directions until another change
+ * puts them in sync again
*/
EXPORT_SYMBOL
-int nfq_tcp_mangle_ipv4(struct pkt_buff *pkt,
+int nfq_tcp_mangle_ipv4(struct pkt_buff *pktb,
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);
+ iph = (struct iphdr *)pktb->network_header;
+ tcph = (struct tcphdr *)(pktb->network_header + iph->ihl*4);
- if (!nfq_ip_mangle(pkt, iph->ihl*4 + tcph->doff*4,
+ if (!nfq_ip_mangle(pktb, iph->ihl*4 + tcph->doff*4,
match_offset, match_len, rep_buffer, rep_len))
return 0;
@@ -207,5 +236,44 @@ int nfq_tcp_mangle_ipv4(struct pkt_buff *pkt,
}
/**
+ * nfq_tcp_mangle_ipv6 - Mangle TCP/IPv6 packet buffer
+ * \param pktb: Pointer to network packet buffer
+ * \param match_offset: Offset from start of TCP data of content that you want
+ * to mangle
+ * \param match_len: Length of the existing content you want to mangle
+ * \param rep_buffer: Pointer to data you want to use to replace current content
+ * \param rep_len: Length of data you want to use to replace current content
+ * \returns 1 for success and 0 for failure. See pktb_mangle() for failure case
+ * \note This function updates the IPv6 length and recalculates the TCP
+ * checksum for you.
+ * \warning After changing the length of a TCP message, the application will
+ * need to mangle sequence numbers in both directions until another change
+ * puts them in sync again
+ */
+EXPORT_SYMBOL
+int nfq_tcp_mangle_ipv6(struct pkt_buff *pktb,
+ unsigned int match_offset, unsigned int match_len,
+ const char *rep_buffer, unsigned int rep_len)
+{
+ struct ip6_hdr *ip6h;
+ struct tcphdr *tcph;
+
+ ip6h = (struct ip6_hdr *)pktb->network_header;
+ tcph = (struct tcphdr *)(pktb->transport_header);
+ if (!tcph)
+ return 0;
+
+ if (!nfq_ip6_mangle(pktb,
+ pktb->transport_header - pktb->network_header +
+ tcph->doff * 4,
+ match_offset, match_len, rep_buffer, rep_len))
+ return 0;
+
+ nfq_tcp_compute_checksum_ipv6(tcph, ip6h);
+
+ return 1;
+}
+
+/**
* @}
*/
diff --git a/src/extra/udp.c b/src/extra/udp.c
index fed23e2..f232127 100644
--- a/src/extra/udp.c
+++ b/src/extra/udp.c
@@ -20,6 +20,7 @@
#include <libnetfilter_queue/libnetfilter_queue.h>
#include <libnetfilter_queue/libnetfilter_queue_udp.h>
#include <libnetfilter_queue/libnetfilter_queue_ipv4.h>
+#include <libnetfilter_queue/libnetfilter_queue_ipv6.h>
#include <libnetfilter_queue/pktbuff.h>
#include "internal.h"
@@ -31,10 +32,12 @@
/**
* nfq_udp_get_hdr - get the UDP header.
- * \param pktb: Pointer to network packet buffer
+ * \param pktb: Pointer to userspace network packet buffer
*
- * This function returns NULL if invalid UDP header is found. On success,
- * it returns the UDP header.
+ * \returns validated pointer to the UDP header or NULL if the UDP header was
+ * not set or if a minimal length check fails.
+ * \note You have to call nfq_ip_set_transport_header() or
+ * nfq_ip6_set_transport_header() first to set the UDP header.
*/
EXPORT_SYMBOL
struct udphdr *nfq_udp_get_hdr(struct pkt_buff *pktb)
@@ -43,7 +46,7 @@ struct udphdr *nfq_udp_get_hdr(struct pkt_buff *pktb)
return NULL;
/* No room for the UDP header. */
- if (pktb->tail - pktb->transport_header < sizeof(struct udphdr))
+ if (pktb_tail(pktb) - pktb->transport_header < sizeof(struct udphdr))
return NULL;
return (struct udphdr *)pktb->transport_header;
@@ -52,7 +55,8 @@ struct udphdr *nfq_udp_get_hdr(struct pkt_buff *pktb)
/**
* nfq_udp_get_payload - get the UDP packet payload.
* \param udph: Pointer to UDP header
- * \param pktb: Pointer to network packet buffer
+ * \param pktb: Pointer to userspace network packet buffer
+ * \returns Pointer to the UDP payload, or NULL if malformed UDP packet.
*/
EXPORT_SYMBOL
void *nfq_udp_get_payload(struct udphdr *udph, struct pkt_buff *pktb)
@@ -64,7 +68,7 @@ void *nfq_udp_get_payload(struct udphdr *udph, struct pkt_buff *pktb)
return NULL;
/* malformed UDP packet. */
- if (pktb->transport_header + len > pktb->tail)
+ if (pktb->transport_header + len > pktb_tail(pktb))
return NULL;
return pktb->transport_header + sizeof(struct udphdr);
@@ -73,23 +77,32 @@ void *nfq_udp_get_payload(struct udphdr *udph, struct pkt_buff *pktb)
/**
* nfq_udp_get_payload_len - get the udp packet payload.
* \param udph: Pointer to UDP header
- * \param pktb: Pointer to network packet buffer
+ * \param pktb: Pointer to userspace network packet buffer
+ * \returns Length of UDP payload (user data)
*/
EXPORT_SYMBOL
unsigned int nfq_udp_get_payload_len(struct udphdr *udph, struct pkt_buff *pktb)
{
- return pktb->tail - pktb->transport_header;
+ return pktb_tail(pktb) - pktb->transport_header - sizeof(struct udphdr);
}
/**
- * nfq_udp_set_checksum_ipv4 - computes a IPv4/TCP packet's segment
- * \param iphdrp: pointer to the ip header
- * \param ippayload: payload of the ip packet
+ * \defgroup udp_internals Internal UDP functions
*
- * \returns the checksum of the udp segment.
+ * Most user-space programs will never need these.
*
- * \see nfq_pkt_compute_ip_checksum
- * \see nfq_pkt_compute_udp_checksum
+ * @{
+ */
+
+/**
+ * nfq_udp_compute_checksum_ipv4 - sets up the UDP checksum in a UDP/IPv4 packet
+ * \param udph: pointer to the UDP header
+ * \param iph: pointer to the IPv4 header
+ * \note
+ * nfq_udp_mangle_ipv4() invokes this function.
+ * As long as developers always use __nfq_udp_mangle_ipv4__ when changing the
+ * content of a UDP message, there is no need to call
+ * __nfq_udp_compute_checksum_ipv4__.
*/
EXPORT_SYMBOL
void nfq_udp_compute_checksum_ipv4(struct udphdr *udph, struct iphdr *iph)
@@ -100,14 +113,14 @@ void nfq_udp_compute_checksum_ipv4(struct udphdr *udph, struct iphdr *iph)
}
/**
- * nfq_udp_set_checksum_ipv6 - computes a IPv6/TCP packet's segment
- * \param iphdrp: pointer to the ip header
- * \param ippayload: payload of the ip packet
- *
- * \returns the checksum of the udp segment.
- *
- * \see nfq_pkt_compute_ip_checksum
- * \see nfq_pkt_compute_udp_checksum
+ * nfq_udp_compute_checksum_ipv6 - sets up the UDP checksum in a UDP/IPv6 packet
+ * \param udph: pointer to the UDP header
+ * \param ip6h: pointer to the IPv6 header
+ * \note
+ * nfq_udp_mangle_ipv6() invokes this function.
+ * As long as developers always use __nfq_udp_mangle_ipv6__ when changing the
+ * content of a UDP message, there is no need to call
+ * __nfq_udp_compute_checksum_ipv6__.
*/
EXPORT_SYMBOL
void nfq_udp_compute_checksum_ipv6(struct udphdr *udph, struct ip6_hdr *ip6h)
@@ -118,6 +131,10 @@ void nfq_udp_compute_checksum_ipv6(struct udphdr *udph, struct ip6_hdr *ip6h)
}
/**
+ * @}
+ */
+
+/**
* nfq_udp_mangle_ipv4 - Mangle UDP/IPv4 packet buffer
* \param pktb: Pointer to network packet buffer
* \param match_offset: Offset from start of UDP data of content that you want
@@ -130,19 +147,19 @@ void nfq_udp_compute_checksum_ipv6(struct udphdr *udph, struct ip6_hdr *ip6h)
* checksums for you.
*/
EXPORT_SYMBOL
-int nfq_udp_mangle_ipv4(struct pkt_buff *pkt,
+int nfq_udp_mangle_ipv4(struct pkt_buff *pktb,
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);
+ iph = (struct iphdr *)pktb->network_header;
+ udph = (struct udphdr *)(pktb->network_header + iph->ihl*4);
udph->len = htons(ntohs(udph->len) + rep_len - match_len);
- if (!nfq_ip_mangle(pkt, iph->ihl*4 + sizeof(struct udphdr),
+ if (!nfq_ip_mangle(pktb, iph->ihl*4 + sizeof(struct udphdr),
match_offset, match_len, rep_buffer, rep_len))
return 0;
@@ -152,11 +169,51 @@ int nfq_udp_mangle_ipv4(struct pkt_buff *pkt,
}
/**
+ * nfq_udp_mangle_ipv6 - Mangle UDP/IPv6 packet buffer
+ * \param pktb: Pointer to network packet buffer
+ * \param match_offset: Offset from start of UDP data of content that you want
+ * to mangle
+ * \param match_len: Length of the existing content you want to mangle
+ * \param rep_buffer: Pointer to data you want to use to replace current content
+ * \param rep_len: Length of data you want to use to replace current content
+ * \returns 1 for success and 0 for failure. See pktb_mangle() for failure case
+ * \note This function updates the IPv6 and UDP lengths and recalculates the UDP
+ * checksum for you.
+ */
+EXPORT_SYMBOL
+int nfq_udp_mangle_ipv6(struct pkt_buff *pktb,
+ unsigned int match_offset, unsigned int match_len,
+ const char *rep_buffer, unsigned int rep_len)
+{
+ struct ip6_hdr *ip6h;
+ struct udphdr *udph;
+
+ ip6h = (struct ip6_hdr *)pktb->network_header;
+ udph = (struct udphdr *)(pktb->transport_header);
+ if (!udph)
+ return 0;
+
+ udph->len = htons(ntohs(udph->len) + rep_len - match_len);
+
+ if (!nfq_ip6_mangle(pktb,
+ pktb->transport_header - pktb->network_header +
+ sizeof(struct udphdr),
+ match_offset, match_len, rep_buffer, rep_len))
+ return 0;
+
+ nfq_udp_compute_checksum_ipv6(udph, ip6h);
+
+ return 1;
+}
+
+/**
* nfq_pkt_snprintf_udp_hdr - print udp header into one buffer in a humnan
* readable way
* \param buf: pointer to buffer that is used to print the object
* \param size: size of the buffer (or remaining room in it).
- * \param udp: pointer to a valid udp header.
+ * \param udph: pointer to a valid udp header.
+ * \returns The number of characters notionally written (excluding trailing NUL)
+ * \sa __snprintf__(3)
*
*/
EXPORT_SYMBOL
diff --git a/src/internal.h b/src/internal.h
index d968325..ae849d6 100644
--- a/src/internal.h
+++ b/src/internal.h
@@ -23,9 +23,7 @@ struct pkt_buff {
uint8_t *network_header;
uint8_t *transport_header;
- uint8_t *head;
uint8_t *data;
- uint8_t *tail;
uint32_t len;
uint32_t data_len;
@@ -33,4 +31,8 @@ struct pkt_buff {
bool mangled;
};
+static inline uint8_t *pktb_tail(struct pkt_buff *pktb)
+{
+ return pktb->data + pktb->len;
+}
#endif
diff --git a/src/libnetfilter_queue.c b/src/libnetfilter_queue.c
index cd14825..3cf9653 100644
--- a/src/libnetfilter_queue.c
+++ b/src/libnetfilter_queue.c
@@ -4,7 +4,7 @@
* (C) 2005, 2008-2010 by Pablo Neira Ayuso <pablo@netfilter.org>
*
* This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2
+ * it under the terms of the GNU General Public License version 2
* as published by the Free Software Foundation (or any later at your option)
*
* This program is distributed in the hope that it will be useful,
@@ -79,7 +79,7 @@
* to receive from and to send packets to kernel-space.
*
* \section using Using libnetfilter_queue
- *
+ *
* To write your own program using libnetfilter_queue, you should start by
* reading (or, if feasible, compiling and stepping through with *gdb*)
* nf-queue.c source file.
@@ -147,7 +147,7 @@ struct nfq_data {
EXPORT_SYMBOL int nfq_errno;
/***********************************************************************
- * low level stuff
+ * low level stuff
***********************************************************************/
static void del_qh(struct nfq_q_handle *qh)
@@ -238,12 +238,12 @@ struct nfnl_handle *nfq_nfnlh(struct nfq_handle *h)
*
* \defgroup Queue Queue handling [DEPRECATED]
*
- * Once libnetfilter_queue library has been initialised (See
+ * Once libnetfilter_queue library has been initialised (See
* \link LibrarySetup \endlink), it is possible to bind the program to a
* specific queue. This can be done by using nfq_create_queue().
*
* The queue can then be tuned via nfq_set_mode() or nfq_set_queue_maxlen().
- *
+ *
* Here's a little code snippet that create queue numbered 0:
* \verbatim
printf("binding this socket to queue '0'\n");
@@ -318,7 +318,7 @@ int nfq_fd(struct nfq_handle *h)
*
* Library initialisation is made in two steps.
*
- * First step is to call nfq_open() to open a NFQUEUE handler.
+ * First step is to call nfq_open() to open a NFQUEUE handler.
*
* Second step is to tell the kernel that userspace queueing is handle by
* NFQUEUE for the selected protocol. This is made by calling nfq_unbind_pf()
@@ -387,7 +387,7 @@ struct nfq_handle *nfq_open(void)
* \param nfnlh Netfilter netlink connection handle obtained by calling nfnl_open()
*
* This function obtains a netfilter queue connection handle using an existing
- * netlink connection. This function is used internally to implement
+ * netlink connection. This function is used internally to implement
* nfq_open(), and should typically not be called directly.
*
* \return a pointer to a new queue handle or NULL on failure.
@@ -409,7 +409,7 @@ struct nfq_handle *nfq_open_nfnl(struct nfnl_handle *nfnlh)
memset(h, 0, sizeof(*h));
h->nfnlh = nfnlh;
- h->nfnlssh = nfnl_subsys_open(h->nfnlh, NFNL_SUBSYS_QUEUE,
+ h->nfnlssh = nfnl_subsys_open(h->nfnlh, NFNL_SUBSYS_QUEUE,
NFQNL_MSG_MAX, 0);
if (!h->nfnlssh) {
/* FIXME: nfq_errno */
@@ -446,7 +446,7 @@ out_free:
*
* This function closes the nfqueue handler and free associated resources.
*
- * \return 0 on success, non-zero on failure.
+ * \return 0 on success, non-zero on failure.
*/
EXPORT_SYMBOL
int nfq_close(struct nfq_handle *h)
@@ -513,10 +513,10 @@ int nfq_unbind_pf(struct nfq_handle *h, uint16_t pf)
* \return a nfq_q_handle pointing to the newly created queue
*
* Creates a new queue handle, and returns it. The new queue is identified by
- * #num, and the callback specified by #cb will be called for each enqueued
- * packet. The #data argument will be passed unchanged to the callback. If
- * a queue entry with id #num already exists, this function will return failure
- * and the existing entry is unchanged.
+ * \b num, and the callback specified by \b cb will be called for each enqueued
+ * packet. The \b data argument will be passed unchanged to the callback. If
+ * a queue entry with id \b num already exists,
+ * this function will return failure and the existing entry is unchanged.
*
* The nfq_callback type is defined in libnetfilter_queue.h as:
* \verbatim
@@ -651,7 +651,7 @@ int nfq_set_mode(struct nfq_q_handle *qh, uint8_t mode, uint32_t range)
* nfq_set_queue_flags - set flags (options) for the kernel queue
* \param qh Netfilter queue handle obtained by call to nfq_create_queue().
* \param mask specifies which flag bits to modify
- * \param flag bitmask of flags
+ * \param flags bitmask of flags
*
* Existing flags, that you may want to combine, are:
*
@@ -830,14 +830,14 @@ static int __set_verdict(struct nfq_q_handle *qh, uint32_t id,
*/
/**
- * nfq_set_verdict - issue a verdict on a packet
+ * nfq_set_verdict - issue a verdict on a packet
* \param qh Netfilter queue handle obtained by call to nfq_create_queue().
* \param id ID assigned to packet by netfilter.
* \param verdict verdict to return to netfilter (NF_ACCEPT, NF_DROP)
- * \param data_len number of bytes of data pointed to by #buf
+ * \param data_len number of bytes of data pointed to by \b buf
* \param buf the buffer that contains the packet data
*
- * Can be obtained by:
+ * Can be obtained by:
* \verbatim
int id;
struct nfqnl_msg_packet_hdr *ph = nfq_get_msg_packet_hdr(tb);
@@ -867,7 +867,7 @@ int nfq_set_verdict(struct nfq_q_handle *qh, uint32_t id,
* \param id ID assigned to packet by netfilter.
* \param verdict verdict to return to netfilter (NF_ACCEPT, NF_DROP)
* \param mark mark to put on packet
- * \param data_len number of bytes of data pointed to by #buf
+ * \param data_len number of bytes of data pointed to by \b buf
* \param buf the buffer that contains the packet data
*/
EXPORT_SYMBOL
@@ -886,7 +886,7 @@ int nfq_set_verdict2(struct nfq_q_handle *qh, uint32_t id,
* \param verdict verdict to return to netfilter (NF_ACCEPT, NF_DROP)
*
* Unlike nfq_set_verdict, the verdict is applied to all queued packets
- * whose packet id is smaller or equal to #id.
+ * whose packet id is smaller or equal to \b id.
*
* batch support was added in Linux 3.1.
* These functions will fail silently on older kernels.
@@ -920,7 +920,7 @@ int nfq_set_verdict_batch2(struct nfq_q_handle *qh, uint32_t id,
* \param id ID assigned to packet by netfilter.
* \param verdict verdict to return to netfilter (NF_ACCEPT, NF_DROP)
* \param mark the mark to put on the packet, in network byte order.
- * \param data_len number of bytes of data pointed to by #buf
+ * \param data_len number of bytes of data pointed to by \b buf
* \param buf the buffer that contains the packet data
*
* \return -1 on error; >= 0 otherwise.
@@ -944,7 +944,7 @@ int nfq_set_verdict_mark(struct nfq_q_handle *qh, uint32_t id,
/*************************************************************
- * Message parsing functions
+ * Message parsing functions
*************************************************************/
/**
@@ -1065,7 +1065,7 @@ uint32_t nfq_get_outdev(struct nfq_data *nfad)
* The index of the physical device the queued packet will be sent out.
* If the returned index is 0, the packet is destined for localhost or the
* physical output interface is not yet known (ie. PREROUTING?).
- *
+ *
* \return The index of physical interface that the packet output will be routed out.
*/
EXPORT_SYMBOL
@@ -1081,10 +1081,10 @@ uint32_t nfq_get_physoutdev(struct nfq_data *nfad)
* \param nfad Netlink packet data handle passed to callback function
* \param name pointer to the buffer to receive the interface name;
* not more than \c IFNAMSIZ bytes will be copied to it.
- * \return -1 in case of error, >0 if it succeed.
+ * \return -1 in case of error, >0 if it succeed.
*
* To use a nlif_handle, You need first to call nlif_open() and to open
- * an handler. Don't forget to store the result as it will be used
+ * an handler. Don't forget to store the result as it will be used
* during all your program life:
* \verbatim
h = nlif_open();
@@ -1101,7 +1101,7 @@ uint32_t nfq_get_physoutdev(struct nfq_data *nfad)
* libnfnetlink is able to update the interface mapping when a new interface
* appears. To do so, you need to call nlif_catch() on the handler after each
* interface related event. The simplest way to get and treat event is to run
- * a select() or poll() against the nlif file descriptor. To get this file
+ * a select() or poll() against the nlif file descriptor. To get this file
* descriptor, you need to use nlif_fd:
* \verbatim
if_fd = nlif_fd(h);
@@ -1130,7 +1130,7 @@ int nfq_get_indev_name(struct nlif_handle *nlif_handle,
*
* See nfq_get_indev_name() documentation for nlif_handle usage.
*
- * \return -1 in case of error, > 0 if it succeed.
+ * \return -1 in case of error, > 0 if it succeed.
*/
EXPORT_SYMBOL
int nfq_get_physindev_name(struct nlif_handle *nlif_handle,
@@ -1150,7 +1150,7 @@ int nfq_get_physindev_name(struct nlif_handle *nlif_handle,
*
* See nfq_get_indev_name() documentation for nlif_handle usage.
*
- * \return -1 in case of error, > 0 if it succeed.
+ * \return -1 in case of error, > 0 if it succeed.
*/
EXPORT_SYMBOL
int nfq_get_outdev_name(struct nlif_handle *nlif_handle,
@@ -1170,7 +1170,7 @@ int nfq_get_outdev_name(struct nlif_handle *nlif_handle,
*
* See nfq_get_indev_name() documentation for nlif_handle usage.
*
- * \return -1 in case of error, > 0 if it succeed.
+ * \return -1 in case of error, > 0 if it succeed.
*/
EXPORT_SYMBOL
@@ -1184,7 +1184,7 @@ int nfq_get_physoutdev_name(struct nlif_handle *nlif_handle,
/**
* nfq_get_packet_hw
*
- * get hardware address
+ * get hardware address
*
* \param nfad Netlink packet data handle passed to callback function
*
@@ -1213,6 +1213,7 @@ struct nfqnl_msg_packet_hw *nfq_get_packet_hw(struct nfq_data *nfad)
/**
* nfq_get_uid - get the UID of the user the packet belongs to
* \param nfad Netlink packet data handle passed to callback function
+ * \param uid Set to UID on return
*
* \warning If the NFQA_CFG_F_GSO flag is not set, then fragmented packets
* may be pushed into the queue. In this case, only one fragment will have the
@@ -1233,6 +1234,7 @@ int nfq_get_uid(struct nfq_data *nfad, uint32_t *uid)
/**
* nfq_get_gid - get the GID of the user the packet belongs to
* \param nfad Netlink packet data handle passed to callback function
+ * \param gid Set to GID on return
*
* \warning If the NFQA_CFG_F_GSO flag is not set, then fragmented packets
* may be pushed into the queue. In this case, only one fragment will have the
@@ -1277,7 +1279,7 @@ int nfq_get_secctx(struct nfq_data *nfad, unsigned char **secdata)
}
/**
- * nfq_get_payload - get payload
+ * nfq_get_payload - get payload
* \param nfad Netlink packet data handle passed to callback function
* \param data Pointer of pointer that will be pointed to the payload
*
diff --git a/src/nlmsg.c b/src/nlmsg.c
index c40a9e4..4f09bf6 100644
--- a/src/nlmsg.c
+++ b/src/nlmsg.c
@@ -34,11 +34,39 @@
* nfq_nlmsg_verdict_put - Put a verdict into a Netlink message
* \param nlh Pointer to netlink message
* \param id ID assigned to packet by netfilter
- * \param verdict verdict to return to netfilter (NF_ACCEPT, NF_DROP)
+ * \param verdict verdict to return to netfilter (see \b Verdicts below)
+ * \par Verdicts
+ * __NF_DROP__ Drop the packet. This is final.
+ * \n
+ * __NF_ACCEPT__ Accept the packet. Processing of the current base chain
+ * and any called chains terminates,
+ * but the packet may still be processed by subsequently invoked base chains.
+ * \n
+ * __NF_STOP__ Like __NF_ACCEPT__, but skip any further base chains using the
+ * current hook.
+ * \n
+ * __NF_REPEAT__ Like __NF_ACCEPT__, but re-queue this packet to the
+ * current base chain. One way to prevent a re-queueing loop is to
+ * also set a packet mark using nfq_nlmsg_verdict_put_mark() and have the
+ * program test for this mark in \c attr[NFQA_MARK]; or have the nefilter rules
+ * do this test.
+ * \n
+ * __NF_QUEUE_NR__(*new_queue*) Like __NF_ACCEPT__, but queue this packet to
+ * queue number *new_queue*. As with the command-line \b queue \b num verdict,
+ * if no process is listening to that queue then the packet is discarded; but
+ * again like with the command-line, one may OR in a flag to bypass *new_queue*
+ * if there is no listener, as in this snippet:
+ * \verbatim
+ nfq_nlmsg_verdict_put(nlh, id, NF_QUEUE_NR(new_queue) |
+ NF_VERDICT_FLAG_QUEUE_BYPASS);
+\endverbatim
*
- * See examples/nf-queue.c, line 46 for an example of how to use this function.
+ * See examples/nf-queue.c, line
+ * <a class="el" href="nf-queue_8c_source.html#l00046">46</a>
+ * for an example of how to use this function in context.
* The calling sequence is \b main --> \b mnl_cb_run --> \b queue_cb -->
* \b nfq_send_verdict --> \b nfq_nlmsg_verdict_put
+ * (\b cb being short for \b callback).
*/
EXPORT_SYMBOL
void nfq_nlmsg_verdict_put(struct nlmsghdr *nlh, int id, int verdict)
@@ -90,14 +118,13 @@ EXPORT_SYMBOL
pktb = pktb_alloc(AF_INET, payload, plen, 255);
// (decide that this packet needs mangling)
nfq_udp_mangle_ipv4(pktb, match_offset, match_len, rep_data, rep_len);
- // Update IP Datagram length
- plen += rep_len - match_len;
+ // nfq_udp_mangle_ipv4 updates packet length, no need to track locally
// Eventually nfq_send_verdict (line 39) gets called
// The received packet may or may not have been modified.
// Add this code before nfq_nlmsg_verdict_put call:
if (pktb_mangled(pktb))
- nfq_nlmsg_verdict_put_pkt(nlh, pktb_data(pktb), plen);
+ nfq_nlmsg_verdict_put_pkt(nlh, pktb_data(pktb), pktb_len(pktb));
\endverbatim
*/
void nfq_nlmsg_verdict_put_pkt(struct nlmsghdr *nlh, const void *pkt,
@@ -236,9 +263,7 @@ static int nfq_pkt_parse_attr_cb(const struct nlattr *attr, void *data)
* nfq_nlmsg_parse - set packet attributes from netlink message
* \param nlh netlink message that you want to read.
* \param attr pointer to array of attributes to set.
- *
- * This function returns MNL_CB_ERROR if any error occurs, or MNL_CB_OK on
- * success.
+ * \returns MNL_CB_OK on success or MNL_CB_ERROR if any error occurs.
*/
EXPORT_SYMBOL
int nfq_nlmsg_parse(const struct nlmsghdr *nlh, struct nlattr **attr)