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/ipv6.c | 149 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 149 insertions(+) create mode 100644 src/extra/ipv6.c (limited to 'src/extra/ipv6.c') 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); + +/** + * @} + */ -- cgit v1.2.3