diff options
Diffstat (limited to 'proto_ipv6_routing.c')
-rw-r--r-- | proto_ipv6_routing.c | 163 |
1 files changed, 163 insertions, 0 deletions
diff --git a/proto_ipv6_routing.c b/proto_ipv6_routing.c new file mode 100644 index 0000000..735f976 --- /dev/null +++ b/proto_ipv6_routing.c @@ -0,0 +1,163 @@ +/* + * netsniff-ng - the packet sniffing beast + * Copyright 2012 Markus Amend <markus@netsniff-ng.org>, Deutsche Flugsicherung GmbH + * Subject to the GPL, version 2. + * + * IPv6 Routing Header described in RFC2460 + */ + +#include <stdio.h> +#include <stdint.h> +#include <netinet/in.h> /* for ntohs() and "struct in6_addr" */ +#include <arpa/inet.h> /* for inet_ntop() */ + +#include "proto.h" +#include "protos.h" +#include "dissector_eth.h" +#include "built_in.h" +#include "pkt_buff.h" + +#define ROUTING_HEADER_TYPE_0 0x00 + +struct routinghdr { + uint8_t h_next_header; + uint8_t h_hdr_ext_len; + uint8_t h_routing_type; + uint8_t h_segments_left; +} __packed; + +struct routinghdr_0 { + uint32_t reserved; + uint32_t addresses[0]; +} __packed; + +static void dissect_routinghdr_type_0(struct pkt_buff *pkt, + ssize_t *data_len, int less) +{ + uint8_t num_addr; + char address[INET6_ADDRSTRLEN]; + struct in6_addr *addr; + struct routinghdr_0 *routing_0; + + routing_0 = (struct routinghdr_0 *) pkt_pull(pkt, sizeof(*routing_0)); + *data_len -= sizeof(*routing_0); + if (routing_0 == NULL || *data_len > pkt_len(pkt) || *data_len < 0) + return; + + if (less) { + tprintf("Addresses (%lu)", *data_len / sizeof(struct in6_addr)); + return; + } + + tprintf("Res (0x%x)", routing_0->reserved); + + num_addr = *data_len / sizeof(*addr); + + while (num_addr--) { + addr = (struct in6_addr *) pkt_pull(pkt, sizeof(*addr)); + *data_len -= sizeof(*addr); + if (addr == NULL || *data_len > pkt_len(pkt) || *data_len < 0) + return; + + tprintf("\n\t Address: %s", + inet_ntop(AF_INET6, addr, address, + sizeof(address))); + } +} + +static inline void dissect_routinghdr_type_0_norm(struct pkt_buff *pkt, + ssize_t *data_len) +{ + dissect_routinghdr_type_0(pkt, data_len, 0); +} + +static inline void dissect_routinghdr_type_0_less(struct pkt_buff *pkt, + ssize_t *data_len) +{ + dissect_routinghdr_type_0(pkt, data_len, 1); +} + +static void routing(struct pkt_buff *pkt) +{ + uint16_t hdr_ext_len; + ssize_t data_len; + struct routinghdr *routing; + + routing = (struct routinghdr *) pkt_pull(pkt, sizeof(*routing)); + if (routing == NULL) + return; + + /* Total Header Length in Bytes */ + hdr_ext_len = (routing->h_hdr_ext_len + 1) * 8; + /* Data length in Bytes */ + data_len = hdr_ext_len - sizeof(*routing); + + tprintf("\t [ Routing "); + tprintf("NextHdr (%u), ", routing->h_next_header); + if (data_len > pkt_len(pkt) || data_len < 0){ + tprintf("HdrExtLen (%u, %u Bytes %s), ", routing->h_hdr_ext_len, + hdr_ext_len, colorize_start_full(black, red) + "invalid" colorize_end()); + return; + } + tprintf("HdrExtLen (%u, %u Bytes), ", routing->h_hdr_ext_len, + hdr_ext_len); + tprintf("Type (%u), ", routing->h_routing_type); + tprintf("Left (%u), ", routing->h_segments_left); + + switch (routing->h_routing_type) { + case ROUTING_HEADER_TYPE_0: + dissect_routinghdr_type_0_norm(pkt, &data_len); + break; + default: + tprintf("Type %u is unknown", routing->h_routing_type); + } + + tprintf(" ]\n"); + + if (data_len > pkt_len(pkt) || data_len < 0) + return; + + pkt_pull(pkt, data_len); + pkt_set_proto(pkt, ð_lay3, routing->h_next_header); +} + +static void routing_less(struct pkt_buff *pkt) +{ + uint16_t hdr_ext_len; + ssize_t data_len; + struct routinghdr *routing; + + routing = (struct routinghdr *) pkt_pull(pkt, sizeof(*routing)); + if (routing == NULL) + return; + + /* Total Header Length in Bytes */ + hdr_ext_len = (routing->h_hdr_ext_len + 1) * 8; + /* Data length in Bytes */ + data_len = hdr_ext_len - sizeof(*routing); + if (data_len > pkt_len(pkt) || data_len < 0) + return; + + tprintf(" Routing "); + + switch (routing->h_routing_type) { + case ROUTING_HEADER_TYPE_0: + dissect_routinghdr_type_0_less(pkt, &data_len); + break; + default: + tprintf("Type %u is unknown", routing->h_routing_type); + } + + if (data_len > pkt_len(pkt) || data_len < 0) + return; + + pkt_pull(pkt, data_len); + pkt_set_proto(pkt, ð_lay3, routing->h_next_header); +} + +struct protocol ipv6_routing_ops = { + .key = 0x2B, + .print_full = routing, + .print_less = routing_less, +}; |