From f40eabb01163f383e2471942da45f32361031e39 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Mon, 14 May 2012 13:14:14 +0200 Subject: add pkt_buff and protocol helper functions Signed-off-by: Pablo Neira Ayuso --- src/extra/checksum.c | 78 +++++++++++++++++++++++ src/extra/ipv4.c | 122 +++++++++++++++++++++++++++++++++++ src/extra/ipv6.c | 149 +++++++++++++++++++++++++++++++++++++++++++ src/extra/pktbuff.c | 142 +++++++++++++++++++++++++++++++++++++++++ src/extra/tcp.c | 175 +++++++++++++++++++++++++++++++++++++++++++++++++++ src/extra/udp.c | 132 ++++++++++++++++++++++++++++++++++++++ 6 files changed, 798 insertions(+) create mode 100644 src/extra/checksum.c create mode 100644 src/extra/ipv4.c create mode 100644 src/extra/ipv6.c create mode 100644 src/extra/pktbuff.c create mode 100644 src/extra/tcp.c create mode 100644 src/extra/udp.c (limited to 'src/extra') diff --git a/src/extra/checksum.c b/src/extra/checksum.c new file mode 100644 index 0000000..d0c4167 --- /dev/null +++ b/src/extra/checksum.c @@ -0,0 +1,78 @@ +/* + * (C) 2012 by Pablo Neira Ayuso + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This code has been sponsored by Vyatta Inc. + */ + +#include +#include +#include +#include +#include + +#include + +#include "internal.h" + +uint16_t checksum(uint32_t sum, uint16_t *buf, int size) +{ + while (size > 1) { + sum += *buf++; + size -= sizeof(uint16_t); + } + if (size) + sum += *(uint8_t *)buf; + + sum = (sum >> 16) + (sum & 0xffff); + sum += (sum >>16); + + return (uint16_t)(~sum); +} + +uint16_t checksum_tcpudp_ipv4(struct iphdr *iph) +{ + uint32_t sum = 0; + uint32_t iph_len = iph->ihl*4; + uint32_t len = ntohs(iph->tot_len) - iph_len; + uint8_t *payload = (uint8_t *)iph + iph_len; + + sum += (iph->saddr >> 16) & 0xFFFF; + sum += (iph->saddr) & 0xFFFF; + sum += (iph->daddr >> 16) & 0xFFFF; + sum += (iph->daddr) & 0xFFFF; + sum += htons(IPPROTO_TCP); + sum += htons(len); + + return checksum(sum, (uint16_t *)payload, len); +} + +uint16_t checksum_tcpudp_ipv6(struct ip6_hdr *ip6h, void *transport_hdr) +{ + uint32_t sum = 0; + uint32_t hdr_len = (uint32_t *)transport_hdr - (uint32_t *)ip6h; + uint32_t len = ip6h->ip6_plen - hdr_len; + 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; + } + for (i=0; i<8; i++) { + sum += (ip6h->ip6_dst.s6_addr16[i] >> 16) & 0xFFFF; + sum += (ip6h->ip6_dst.s6_addr16[i]) & 0xFFFF; + } + sum += htons(IPPROTO_TCP); + sum += htons(ip6h->ip6_plen); + + return checksum(sum, (uint16_t *)payload, len); +} + +/** + * @} + */ diff --git a/src/extra/ipv4.c b/src/extra/ipv4.c new file mode 100644 index 0000000..200a20e --- /dev/null +++ b/src/extra/ipv4.c @@ -0,0 +1,122 @@ +/* + * (C) 2012 by Pablo Neira Ayuso + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This code has been sponsored by Vyatta Inc. + */ + +#include +#include +#include + +#include +#include +#include + +#include "internal.h" + +/** + * \defgroup ipv4 IPv4 helper functions + * @{ + */ + +/** + * nfq_ip_get_hdr - get IPv4 header + * \param pktb: pointer to network packet buffer + * + * 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. + */ +struct iphdr *nfq_ip_get_hdr(struct pkt_buff *pktb) +{ + struct iphdr *iph; + unsigned int pktlen = pktb->tail - pktb->network_header; + + /* Not enough room for IPv4 header. */ + if (pktlen < sizeof(struct iphdr)) + return NULL; + + iph = (struct iphdr *)pktb->network_header; + + /* Not IPv4 packet. */ + if (iph->version != 4) + return NULL; + + /* Malformed IPv4 total length field. */ + if (ntohs(iph->tot_len) > pktlen) + return NULL; + + return iph; +} +EXPORT_SYMBOL(nfq_ip_get_hdr); + +/** + * nfq_ip_get_payload - get the IPv4 packet payload + * \param pktb: pointer to network packet buffer + * \param iph: the pointer to the IPv4 header + */ +int nfq_ip_set_transport_header(struct pkt_buff *pktb, struct iphdr *iph) +{ + int doff = iph->ihl * 4; + + /* Wrong offset to IPv4 payload. */ + if ((int)pktb->len - doff <= 0) + return -1; + + pktb->transport_header = pktb->network_header + doff; + return 0; +} +EXPORT_SYMBOL(nfq_ip_set_transport_header); + +/** + * nfq_ip_set_checksum - set IPv4 checksum + * \param iph: pointer to the IPv4 header + * + * \returns the checksum of the ip packet. + * + * \note Call to this function if you modified the IPv4 header to update the + * checksum. + */ +void nfq_ip_set_checksum(struct iphdr *iph) +{ + uint32_t iph_len = iph->ihl * 4; + + iph->check = 0; + iph->check = checksum(0, (uint16_t *)iph, iph_len); +} +EXPORT_SYMBOL(nfq_ip_set_checksum); + +/** + * 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 + * \param size: size of the buffer (or remaining room in it) + * \param ip: pointer to a valid IPv4 header + * + * This function returns the number of bytes that would have been written in + * case that there is enough room in the buffer. Read snprintf manpage for more + * information to know more about this strange behaviour. + */ +int nfq_ip_snprintf(char *buf, size_t size, const struct iphdr *iph) +{ + int ret; + struct in_addr src = { iph->saddr }; + struct in_addr dst = { iph->daddr }; + + ret = snprintf(buf, size, "SRC=%s DST=%s LEN=%u TOS=0x%X " + "PREC=0x%X TTL=%u ID=%u PROTO=%u ", + inet_ntoa(src), inet_ntoa(dst), + ntohs(iph->tot_len), IPTOS_TOS(iph->tos), + IPTOS_PREC(iph->tos), iph->ttl, ntohs(iph->id), + iph->protocol); + + return ret; +} +EXPORT_SYMBOL(nfq_ip_snprintf); + +/** + * @} + */ diff --git a/src/extra/ipv6.c b/src/extra/ipv6.c new file mode 100644 index 0000000..0457016 --- /dev/null +++ b/src/extra/ipv6.c @@ -0,0 +1,149 @@ +/* + * (C) 2012 by Pablo Neira Ayuso + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This code has been sponsored by Vyatta Inc. + */ + +#include +#include +#include +#include + +#include +#include +#include + +#include "internal.h" + +/** + * \defgroup ipv6 IPv6 helper functions + * @{ + */ + +/** + * nfq_ip6_get_hdr - get IPv6 header + * \param pktb: pointer to user-space network packet buffer + * + * This funcion returns NULL if an invalid header is found. On sucess, it + * returns a valid pointer to the header. + */ +struct ip6_hdr *nfq_ip6_get_hdr(struct pkt_buff *pktb) +{ + struct ip6_hdr *ip6h; + unsigned int pktlen = pktb->tail - pktb->network_header; + + /* Not enough room for IPv4 header. */ + if (pktlen < sizeof(struct ip6_hdr)) + return NULL; + + ip6h = (struct ip6_hdr *)pktb->network_header; + + /* Not IPv6 packet. */ + if (ip6h->ip6_flow != 0x60) + return NULL; + + return ip6h; +} +EXPORT_SYMBOL(nfq_ip6_get_hdr); + +/** + * nfq_ip6_set_transport_header - set transport header pointer for IPv6 packet + * \param pktb: pointer to user-space network packet buffer + * \param ip6h: pointer to IPv6 header + * \param target: protocol number to find transport header (ie. IPPROTO_*) + * + * This function returns 1 if the protocol has been found and the transport + * header has been set. Otherwise, it returns 0. + */ +int nfq_ip6_set_transport_header(struct pkt_buff *pktb, struct ip6_hdr *ip6h, + uint8_t target) +{ + uint8_t nexthdr = ip6h->ip6_nxt; + uint8_t *cur = (uint8_t *)ip6h + sizeof(struct ip6_hdr); + + while (nexthdr != target) { + struct ip6_ext *ip6_ext; + uint32_t hdrlen; + + /* No more extensions, we're done. */ + if (nexthdr == IPPROTO_NONE) { + cur = NULL; + break; + } + /* No room for extension, bad packet. */ + if (pktb->tail - cur < sizeof(struct ip6_ext)) { + cur = NULL; + break; + } + ip6_ext = (struct ip6_ext *)cur; + + if (nexthdr == IPPROTO_FRAGMENT) { + uint16_t *frag_off; + + /* No room for full fragment header, bad packet. */ + if (pktb->tail - cur < sizeof(struct ip6_frag)) { + cur = NULL; + break; + } + + frag_off = (uint16_t *)cur + + offsetof(struct ip6_frag, ip6f_offlg); + + /* Fragment offset is only 13 bits long. */ + if (htons(*frag_off & ~0x7)) { + /* Not the first fragment, it does not contain + * any headers. + */ + cur = NULL; + break; + } + hdrlen = sizeof(struct ip6_frag); + } else if (nexthdr == IPPROTO_AH) + hdrlen = (ip6_ext->ip6e_len + 2) << 2; + else + hdrlen = ip6_ext->ip6e_len; + + nexthdr = ip6_ext->ip6e_nxt; + cur += hdrlen; + } + pktb->transport_header = cur; + return cur ? 1 : 0; +} +EXPORT_SYMBOL(nfq_ip6_set_transport_header); + +/** + * 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). + * \param ip6_hdr: pointer to a valid IPv6 header. + * + */ +int nfq_ip6_snprintf(char *buf, size_t size, const struct ip6_hdr *ip6h) +{ + int ret; + char src[INET6_ADDRSTRLEN]; + char dst[INET6_ADDRSTRLEN]; + + inet_ntop(AF_INET6, &ip6h->ip6_src, src, INET6_ADDRSTRLEN); + inet_ntop(AF_INET6, &ip6h->ip6_dst, dst, INET6_ADDRSTRLEN); + + ret = snprintf(buf, size, "SRC=%s DST=%s LEN=%Zu TC=0x%X " + "HOPLIMIT=%u FLOWLBL=%u ", + src, dst, + ntohs(ip6h->ip6_plen) + sizeof(struct ip6_hdr), + (ip6h->ip6_flow & 0x0ff00000) >> 20, + ip6h->ip6_hlim, + (ip6h->ip6_flow & 0x000fffff)); + + return ret; +} +EXPORT_SYMBOL(nfq_ip6_snprintf); + +/** + * @} + */ diff --git a/src/extra/pktbuff.c b/src/extra/pktbuff.c new file mode 100644 index 0000000..809953b --- /dev/null +++ b/src/extra/pktbuff.c @@ -0,0 +1,142 @@ +/* + * (C) 2012 by Pablo Neira Ayuso + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This code has been sponsored by Vyatta Inc. + */ + +#include +#include /* for memcpy */ + +#include +#include +#include + +#include "internal.h" + +/** + * \defgroup pktbuff User-space network packet buffer + * + * This library provides the user-space network packet buffer. This abstraction + * is strongly inspired by Linux kernel network buffer, the so-called sk_buff. + */ + +/** + * pktb_alloc - allocate a new packet buffer + * \param family Indicate what family, eg. AF_BRIDGE, AF_INET, AF_INET6, ... + * \param data Pointer to packet data + * \param len Packet length + * \param extra Extra memory in the tail to be allocated (for mangling) + * + * This function returns a packet buffer that contains the packet data and + * some extra memory room in the tail (in case of requested). + * + * \return a pointer to a new queue handle or NULL on failure. + */ +struct pkt_buff * +pktb_alloc(int family, void *data, size_t len, size_t extra) +{ + struct pkt_buff *pktb; + void *pkt_data; + + pktb = calloc(1, sizeof(struct pkt_buff) + len + extra); + if (pktb == NULL) + return NULL; + + /* Better make sure alignment is correct. */ + pkt_data = (uint8_t *)pktb + sizeof(struct pkt_buff); + memcpy(pkt_data, data, len); + + 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: + pktb->network_header = pktb->data; + break; + case AF_BRIDGE: { + struct ethhdr *ethhdr = (struct ethhdr *)pktb->data; + + pktb->mac_header = pktb->data; + + switch(ethhdr->h_proto) { + case ETH_P_IP: + pktb->network_header = pktb->data + ETH_HLEN; + break; + default: + /* This protocol is unsupported. */ + free(pktb); + return NULL; + } + break; + } + } + return pktb; +} + +uint8_t *pktb_data(struct pkt_buff *pktb) +{ + return pktb->data; +} + +uint32_t pktb_len(struct pkt_buff *pktb) +{ + return pktb->len; +} + +void pktb_free(struct pkt_buff *pktb) +{ + free(pktb); +} + +void pktb_push(struct pkt_buff *pktb, unsigned int len) +{ + pktb->data += len; +} + +void pktb_pull(struct pkt_buff *pktb, unsigned int len) +{ + pktb->data -= len; +} + +void pktb_put(struct pkt_buff *pktb, unsigned int len) +{ + pktb->tail += len; +} + +void pktb_trim(struct pkt_buff *pktb, unsigned int len) +{ + pktb->len = len; +} + +unsigned int pktb_tailroom(struct pkt_buff *pktb) +{ + return pktb->data_len - pktb->len; +} + +uint8_t *pktb_mac_header(struct pkt_buff *pktb) +{ + return pktb->mac_header; +} + +uint8_t *pktb_network_header(struct pkt_buff *pktb) +{ + return pktb->network_header; +} + +uint8_t *pktb_transport_header(struct pkt_buff *pktb) +{ + return pktb->transport_header; +} + +/** + * @} + */ diff --git a/src/extra/tcp.c b/src/extra/tcp.c new file mode 100644 index 0000000..9de3748 --- /dev/null +++ b/src/extra/tcp.c @@ -0,0 +1,175 @@ +/* + * (C) 2012 by Pablo Neira Ayuso + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This code has been sponsored by Vyatta Inc. + */ + +#include +#include /* for memcpy */ +#include +#include +#include +#include + +#include +#include +#include + +#include "internal.h" + +/** + * \defgroup tcp TCP helper functions + * @{ + */ + +/** + * nfq_tcp_get - 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. + */ +struct tcphdr *nfq_tcp_get_hdr(struct pkt_buff *pktb) +{ + if (pktb->transport_header == NULL) + return NULL; + + /* No room for the TCP header. */ + if (pktb->tail - pktb->transport_header < sizeof(struct tcphdr)) + return NULL; + + return (struct tcphdr *)pktb->transport_header; +} +EXPORT_SYMBOL(nfq_tcp_get_hdr); + +/** + * 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 + */ +void *nfq_tcp_get_payload(struct tcphdr *tcph, struct pkt_buff *pktb) +{ + unsigned int doff = tcph->doff * 4; + + /* malformed TCP data offset. */ + if (pktb->transport_header + doff >= pktb->tail) + return NULL; + + return pktb->transport_header + doff; +} +EXPORT_SYMBOL(nfq_tcp_get_payload); + +/** + * 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 + */ +unsigned int +nfq_tcp_get_payload_len(struct tcphdr *tcph, struct pkt_buff *pktb) +{ + return pktb->tail - pktb->transport_header; +} +EXPORT_SYMBOL(nfq_tcp_get_payload_len); + +/** + * nfq_tcp_set_checksum_ipv4 - computes IPv4/TCP packet checksum + * \param tcph: pointer to the TCP header + * \param iph: pointer to the IPv4 header + */ +void +nfq_tcp_compute_checksum_ipv4(struct tcphdr *tcph, struct iphdr *iph) +{ + /* checksum field in header needs to be zero for calculation. */ + tcph->check = 0; + tcph->check = checksum_tcpudp_ipv4(iph); +} +EXPORT_SYMBOL(nfq_tcp_compute_checksum_ipv4); + +/** + * nfq_tcp_set_checksum_ipv6 - computes IPv6/TCP packet checksum + * \param tcph: pointer to the TCP header + * \param iph: pointer to the IPv6 header + */ +void +nfq_tcp_compute_checksum_ipv6(struct tcphdr *tcph, struct ip6_hdr *ip6h) +{ + /* checksum field in header needs to be zero for calculation. */ + tcph->check = 0; + tcph->check = checksum_tcpudp_ipv6(ip6h, tcph); +} +EXPORT_SYMBOL(nfq_tcp_compute_checksum_ipv6); + +/* + * The union cast uses a gcc extension to avoid aliasing problems + * (union is compatible to any of its members) + * This means this part of the code is -fstrict-aliasing safe now. + */ +union tcp_word_hdr { + struct tcphdr hdr; + uint32_t words[5]; +}; + +#define tcp_flag_word(tp) ( ((union tcp_word_hdr *)(tp))->words[3]) + +/** + * nfq_pkt_snprintf_tcp_hdr - print tcp 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 tcp: pointer to a valid tcp header. + * + */ +int nfq_tcp_snprintf(char *buf, size_t size, const struct tcphdr *tcph) +{ + int ret, len = 0; + +#define TCP_RESERVED_BITS htonl(0x0F000000) + + ret = snprintf(buf, size, "SPT=%u DPT=%u SEQ=%u ACK=%u " + "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)); + len += ret; + + if (tcph->urg) { + ret = snprintf(buf+len, size-len, "URG "); + len += ret; + } + if (tcph->ack) { + ret = snprintf(buf+len, size-len, "ACK "); + len += ret; + } + if (tcph->psh) { + ret = snprintf(buf+len, size-len, "PSH "); + len += ret; + } + if (tcph->rst) { + ret = snprintf(buf+len, size-len, "RST "); + len += ret; + } + if (tcph->syn) { + ret = snprintf(buf+len, size-len, "SYN "); + len += ret; + } + if (tcph->fin) { + ret = snprintf(buf+len, size-len, "FIN "); + len += ret; + } + /* Not TCP options implemented yet, sorry. */ +} +EXPORT_SYMBOL(nfq_tcp_snprintf); + +/** + * @} + */ diff --git a/src/extra/udp.c b/src/extra/udp.c new file mode 100644 index 0000000..c0b1b7d --- /dev/null +++ b/src/extra/udp.c @@ -0,0 +1,132 @@ +/* + * (C) 2012 by Pablo Neira Ayuso + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This code has been sponsored by Vyatta Inc. + */ + +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "internal.h" + +/** + * \defgroup udp UDP helper functions + * @{ + */ + +/** + * nfq_udp_get_hdr - get the UDP header. + * \param head: pointer to the beginning of the packet + * \param tail: pointer to the tail of the packet + * + * This function returns NULL if invalid UDP header is found. On success, + * it returns the UDP header. + */ +struct udphdr *nfq_udp_get_hdr(struct pkt_buff *pktb) +{ + if (pktb->transport_header == NULL) + return NULL; + + /* No room for the UDP header. */ + if (pktb->tail - pktb->transport_header < sizeof(struct udphdr)) + return NULL; + + return (struct udphdr *)pktb->transport_header; +} +EXPORT_SYMBOL(nfq_udp_get_hdr); + +/** + * nfq_udp_get_payload - get the UDP packet payload. + * \param udph: the pointer to the UDP header. + * \param tail: pointer to the tail of the packet + */ +void *nfq_udp_get_payload(struct udphdr *udph, struct pkt_buff *pktb) +{ + unsigned int doff = udph->len; + + /* malformed UDP data offset. */ + if (pktb->transport_header + doff > pktb->tail) + return NULL; + + return pktb->transport_header + doff; +} +EXPORT_SYMBOL(nfq_udp_get_payload); + +/** + * nfq_udp_get_payload_len - get the udp packet payload. + * \param udp: the pointer to the udp header. + */ +unsigned int nfq_udp_get_payload_len(struct udphdr *udph, struct pkt_buff *pktb) +{ + return pktb->tail - pktb->transport_header; +} +EXPORT_SYMBOL(nfq_udp_get_payload_len); + +/** + * 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 + * + * \returns the checksum of the udp segment. + * + * \see nfq_pkt_compute_ip_checksum + * \see nfq_pkt_compute_udp_checksum + */ +void +nfq_udp_compute_checksum_ipv4(struct udphdr *udph, struct iphdr *iph) +{ + /* checksum field in header needs to be zero for calculation. */ + udph->check = 0; + udph->check = checksum_tcpudp_ipv4(iph); +} +EXPORT_SYMBOL(nfq_udp_compute_checksum_ipv4); + +/** + * 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 + */ +void +nfq_udp_compute_checksum_ipv6(struct udphdr *udph, struct ip6_hdr *ip6h) +{ + /* checksum field in header needs to be zero for calculation. */ + udph->check = 0; + udph->check = checksum_tcpudp_ipv6(ip6h, udph); +} +EXPORT_SYMBOL(nfq_udp_compute_checksum_ipv6); + +/** + * 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. + * + */ +int nfq_udp_snprintf(char *buf, size_t size, const struct udphdr *udph) +{ + return snprintf(buf, size, "SPT=%u DPT=%u ", + htons(udph->source), htons(udph->dest)); +} +EXPORT_SYMBOL(nfq_udp_snprintf); + +/** + * @} + */ -- cgit v1.2.3