diff options
Diffstat (limited to 'dissector_eth.c')
-rw-r--r-- | dissector_eth.c | 219 |
1 files changed, 219 insertions, 0 deletions
diff --git a/dissector_eth.c b/dissector_eth.c new file mode 100644 index 0000000..f352645 --- /dev/null +++ b/dissector_eth.c @@ -0,0 +1,219 @@ +/* + * netsniff-ng - the packet sniffing beast + * Copyright 2009, 2010 Daniel Borkmann. + * Subject to the GPL, version 2. + */ + +#include <stdint.h> + +#include "hash.h" +#include "oui.h" +#include "protos.h" +#include "pkt_buff.h" +#include "dissector.h" +#include "dissector_eth.h" +#include "xmalloc.h" + +struct hash_table eth_lay2; +struct hash_table eth_lay3; + +static struct hash_table eth_ether_types; +static struct hash_table eth_ports_udp; +static struct hash_table eth_ports_tcp; + +struct port { + unsigned int id; + char *port; + struct port *next; +}; + +#define __do_lookup_inline(id, struct_name, hash_ptr, struct_member) \ + ({ \ + struct struct_name *entry = lookup_hash(id, hash_ptr); \ + \ + while (entry && id != entry->id) \ + entry = entry->next; \ + \ + (entry && id == entry->id ? entry->struct_member : 0); \ + }) + +char *lookup_port_udp(unsigned int id) +{ + return __do_lookup_inline(id, port, ð_ports_udp, port); +} + +char *lookup_port_tcp(unsigned int id) +{ + return __do_lookup_inline(id, port, ð_ports_tcp, port); +} + +char *lookup_ether_type(unsigned int id) +{ + return __do_lookup_inline(id, port, ð_ether_types, port); +} + +#ifdef __WITH_PROTOS +static inline void dissector_init_entry(int type) +{ + dissector_set_print_type(ðernet_ops, type); +} + +static inline void dissector_init_exit(int type) +{ + dissector_set_print_type(&none_ops, type); +} + +static void dissector_init_layer_2(int type) +{ + init_hash(ð_lay2); + INSERT_HASH_PROTOS(arp_ops, eth_lay2); + INSERT_HASH_PROTOS(lldp_ops, eth_lay2); + INSERT_HASH_PROTOS(vlan_ops, eth_lay2); + INSERT_HASH_PROTOS(ipv4_ops, eth_lay2); + INSERT_HASH_PROTOS(ipv6_ops, eth_lay2); + INSERT_HASH_PROTOS(QinQ_ops, eth_lay2); + INSERT_HASH_PROTOS(mpls_uc_ops, eth_lay2); + for_each_hash_int(ð_lay2, dissector_set_print_type, type); +} + +static void dissector_init_layer_3(int type) +{ + init_hash(ð_lay3); + INSERT_HASH_PROTOS(icmpv4_ops, eth_lay3); + INSERT_HASH_PROTOS(icmpv6_ops, eth_lay3); + INSERT_HASH_PROTOS(igmp_ops, eth_lay3); + INSERT_HASH_PROTOS(ip_auth_ops, eth_lay3); + INSERT_HASH_PROTOS(ip_esp_ops, eth_lay3); + INSERT_HASH_PROTOS(ipv6_dest_opts_ops, eth_lay3); + INSERT_HASH_PROTOS(ipv6_fragm_ops, eth_lay3); + INSERT_HASH_PROTOS(ipv6_hop_by_hop_ops, eth_lay3); + INSERT_HASH_PROTOS(ipv6_in_ipv4_ops, eth_lay3); + INSERT_HASH_PROTOS(ipv6_mobility_ops, eth_lay3); + INSERT_HASH_PROTOS(ipv6_no_next_header_ops, eth_lay3); + INSERT_HASH_PROTOS(ipv6_routing_ops, eth_lay3); + INSERT_HASH_PROTOS(tcp_ops, eth_lay3); + INSERT_HASH_PROTOS(udp_ops, eth_lay3); + for_each_hash_int(ð_lay3, dissector_set_print_type, type); +} +#else +static inline void dissector_init_entry(int type) {} +static inline void dissector_init_exit(int type) {} +static void dissector_init_layer_2(int type) {} +static void dissector_init_layer_3(int type) {} +#endif /* __WITH_PROTOS */ + +enum ports { + PORTS_UDP, + PORTS_TCP, + PORTS_ETHER, +}; + +static void dissector_init_ports(enum ports which) +{ + FILE *fp; + char buff[128], *ptr, *file; + struct hash_table *table; + struct port *p; + void **pos; + + switch (which) { + case PORTS_UDP: + file = "/etc/netsniff-ng/udp.conf"; + table = ð_ports_udp; + break; + case PORTS_TCP: + file = "/etc/netsniff-ng/tcp.conf"; + table = ð_ports_tcp; + break; + case PORTS_ETHER: + file = "/etc/netsniff-ng/ether.conf"; + table = ð_ether_types; + break; + default: + bug(); + } + + fp = fopen(file, "r"); + if (!fp) + panic("No %s found!\n", file); + + memset(buff, 0, sizeof(buff)); + + while (fgets(buff, sizeof(buff), fp) != NULL) { + buff[sizeof(buff) - 1] = 0; + ptr = buff; + + p = xmalloc(sizeof(*p)); + p->id = strtol(ptr, &ptr, 0); + + if ((ptr = strstr(buff, ", "))) + ptr += strlen(", "); + ptr = strtrim_right(ptr, '\n'); + ptr = strtrim_right(ptr, ' '); + + p->port = xstrdup(ptr); + p->next = NULL; + + pos = insert_hash(p->id, p, table); + if (pos) { + p->next = *pos; + *pos = p; + } + + memset(buff, 0, sizeof(buff)); + } + + fclose(fp); +} + +static int dissector_cleanup_ports(void *ptr) +{ + struct port *tmp, *p = ptr; + + if (!ptr) + return 0; + + while ((tmp = p->next)) { + xfree(p->port); + xfree(p); + p = tmp; + } + + xfree(p->port); + xfree(p); + + return 0; +} + +void dissector_init_ethernet(int fnttype) +{ + dissector_init_entry(fnttype); + dissector_init_layer_2(fnttype); + dissector_init_layer_3(fnttype); + dissector_init_exit(fnttype); + +#ifdef __WITH_PROTOS + dissector_init_oui(); +#endif + dissector_init_ports(PORTS_UDP); + dissector_init_ports(PORTS_TCP); + dissector_init_ports(PORTS_ETHER); +} + +void dissector_cleanup_ethernet(void) +{ + free_hash(ð_lay2); + free_hash(ð_lay3); + + for_each_hash(ð_ether_types, dissector_cleanup_ports); + for_each_hash(ð_ports_udp, dissector_cleanup_ports); + for_each_hash(ð_ports_tcp, dissector_cleanup_ports); + + free_hash(ð_ether_types); + free_hash(ð_ports_udp); + free_hash(ð_ports_tcp); + +#ifdef __WITH_PROTOS + dissector_cleanup_oui(); +#endif +} |