mausezahn: move variable definitions from mops.h to mops.c
[netsniff-ng-new.git] / proto_ipv4.c
blobe522a90f0b706ce0e60ed9f798ba138299bc5995
1 /*
2 * netsniff-ng - the packet sniffing beast
3 * Copyright (C) 2009, 2010 Daniel Borkmann
4 * Copyright (C) 2012 Christoph Jaeger <christoph@netsniff-ng.org>
5 * Subject to the GPL, version 2.
6 */
8 #include <stdio.h>
9 #include <stdint.h>
10 #include <netinet/in.h> /* for ntohs() */
11 #include <arpa/inet.h> /* for inet_ntop() */
13 #include "proto.h"
14 #include "csum.h"
15 #include "dissector_eth.h"
16 #include "ipv4.h"
17 #include "geoip.h"
18 #include "pkt_buff.h"
19 #include "built_in.h"
21 #define FRAG_OFF_RESERVED_FLAG(x) ((x) & 0x8000)
22 #define FRAG_OFF_NO_FRAGMENT_FLAG(x) ((x) & 0x4000)
23 #define FRAG_OFF_MORE_FRAGMENT_FLAG(x) ((x) & 0x2000)
24 #define FRAG_OFF_FRAGMENT_OFFSET(x) ((x) & 0x1fff)
26 /* IP Option Numbers (http://www.iana.org/assignments/ip-parameters) */
27 #define IP_OPT_EOOL 0x00
28 #define IP_OPT_NOP 0x01
30 #define IP_OPT_COPIED_FLAG(x) ((x) & 0x80)
31 #define IP_OPT_CLASS(x) (((x) & 0x60) >> 5)
32 #define IP_OPT_NUMBER(x) ((x) & 0x1F)
34 static void ipv4(struct pkt_buff *pkt)
36 uint16_t csum, frag_off, h_tot_len;
37 char src_ip[INET_ADDRSTRLEN];
38 char dst_ip[INET_ADDRSTRLEN];
39 struct ipv4hdr *ip = (struct ipv4hdr *) pkt_pull(pkt, sizeof(*ip));
40 uint8_t *opt, *trailer;
41 unsigned int trailer_len = 0;
42 ssize_t opts_len, opt_len;
43 const char *country;
44 char *city, *region;
46 if (!ip)
47 return;
49 frag_off = ntohs(ip->h_frag_off);
50 h_tot_len = ntohs(ip->h_tot_len);
51 csum = calc_csum(ip, ip->h_ihl * 4);
53 inet_ntop(AF_INET, &ip->h_saddr, src_ip, sizeof(src_ip));
54 inet_ntop(AF_INET, &ip->h_daddr, dst_ip, sizeof(dst_ip));
56 if ((pkt_len(pkt) + sizeof(*ip)) > h_tot_len) {
57 trailer_len = pkt_len(pkt) + sizeof(*ip) - h_tot_len;
58 trailer = pkt->data + h_tot_len + trailer_len;
61 if (trailer_len) {
62 tprintf(" [ Eth trailer ");
63 while (trailer_len--) {
64 tprintf("%x", *(trailer - trailer_len));
66 tprintf(" ]\n");
69 tprintf(" [ IPv4 ");
70 tprintf("Addr (%s => %s), ", src_ip, dst_ip);
71 tprintf("Proto (%u), ", ip->h_protocol);
72 tprintf("TTL (%u), ", ip->h_ttl);
73 tprintf("TOS (%u), ", ip->h_tos);
74 tprintf("Ver (%u), ", ip->h_version);
75 tprintf("IHL (%u), ", ip->h_ihl);
76 tprintf("Tlen (%u), ", ntohs(ip->h_tot_len));
77 tprintf("ID (%u), ", ntohs(ip->h_id));
78 tprintf("Res (%u), NoFrag (%u), MoreFrag (%u), FragOff (%u), ",
79 FRAG_OFF_RESERVED_FLAG(frag_off) ? 1 : 0,
80 FRAG_OFF_NO_FRAGMENT_FLAG(frag_off) ? 1 : 0,
81 FRAG_OFF_MORE_FRAGMENT_FLAG(frag_off) ? 1 : 0,
82 FRAG_OFF_FRAGMENT_OFFSET(frag_off));
83 tprintf("CSum (0x%.4x) is %s", ntohs(ip->h_check),
84 csum ? colorize_start_full(black, red) "bogus (!)"
85 colorize_end() : "ok");
86 if (csum)
87 tprintf("%s should be 0x%.4x%s", colorize_start_full(black, red),
88 csum_expected(ip->h_check, csum), colorize_end());
89 tprintf(" ]\n");
91 if (geoip_working()) {
92 struct sockaddr_in sas, sad;
94 memset(&sas, 0, sizeof(sas));
95 sas.sin_family = PF_INET;
96 sas.sin_addr.s_addr = ip->h_saddr;
98 memset(&sad, 0, sizeof(sad));
99 sad.sin_family = PF_INET;
100 sad.sin_addr.s_addr = ip->h_daddr;
102 tprintf("\t[ Geo (");
103 if ((country = geoip4_country_name(&sas))) {
104 tprintf("%s", country);
105 if ((region = geoip4_region_name(&sas))) {
106 tprintf(" / %s", region);
107 xfree(region);
109 if ((city = geoip4_city_name(&sas))) {
110 tprintf(" / %s", city);
111 xfree(city);
113 } else {
114 tprintf("local");
116 tprintf(" => ");
117 if ((country = geoip4_country_name(&sad))) {
118 tprintf("%s", country);
119 if ((region = geoip4_region_name(&sad))) {
120 tprintf(" / %s", region);
121 xfree(region);
123 if ((city = geoip4_city_name(&sad))) {
124 tprintf(" / %s", city);
125 xfree(city);
127 } else {
128 tprintf("local");
130 tprintf(") ]\n");
133 opts_len = max_t(uint8_t, ip->h_ihl, sizeof(*ip) / sizeof(uint32_t)) *
134 sizeof(uint32_t) - sizeof(*ip);
136 for (opt = pkt_pull(pkt, opts_len); opt && opts_len > 0; opt++) {
137 tprintf(" [ Option Copied (%u), Class (%u), Number (%u)",
138 IP_OPT_COPIED_FLAG(*opt) ? 1 : 0, IP_OPT_CLASS(*opt),
139 IP_OPT_NUMBER(*opt));
141 switch (*opt) {
142 case IP_OPT_EOOL:
143 case IP_OPT_NOP:
144 tprintf(" ]\n");
145 opts_len--;
146 break;
147 default:
149 * Assuming that EOOL and NOP are the only single-byte
150 * options, treat all other options as variable in
151 * length with a minimum of 2.
153 * TODO: option length might be incorrect in malformed packets,
154 * check and handle that
156 opt_len = *(++opt);
157 if (opt_len < 2 || opt_len > opts_len) {
158 tprintf(", Len (%zd, invalid) ]\n", opt_len);
159 goto out;
160 } else
161 tprintf(", Len (%zd) ]\n", opt_len);
162 opts_len -= opt_len;
163 tprintf(" [ Data hex ");
164 for (opt_len -= 2; opt_len > 0; opt_len--)
165 tprintf(" %.2x", *(++opt));
166 tprintf(" ]\n");
167 break;
170 out:
171 /* cut off everything that is not part of IPv4 payload */
172 /* XXX there could still be an Ethernet trailer included or others */
174 pkt_trim(pkt, pkt_len(pkt) - min(pkt_len(pkt),
175 (ntohs(ip->h_tot_len) - ip->h_ihl * sizeof(uint32_t))));
177 pkt_set_dissector(pkt, &eth_lay3, ip->h_protocol);
180 static void ipv4_less(struct pkt_buff *pkt)
182 char src_ip[INET_ADDRSTRLEN];
183 char dst_ip[INET_ADDRSTRLEN];
184 struct ipv4hdr *ip = (struct ipv4hdr *) pkt_pull(pkt, sizeof(*ip));
186 if (!ip)
187 return;
189 inet_ntop(AF_INET, &ip->h_saddr, src_ip, sizeof(src_ip));
190 inet_ntop(AF_INET, &ip->h_daddr, dst_ip, sizeof(dst_ip));
192 tprintf(" %s/%s Len %u", src_ip, dst_ip,
193 ntohs(ip->h_tot_len));
195 /* cut off IP options and everything that is not part of IPv4 payload */
196 pkt_pull(pkt, max_t(uint8_t, ip->h_ihl, sizeof(*ip) / sizeof(uint32_t))
197 * sizeof(uint32_t) - sizeof(*ip));
198 /* XXX there could still be an Ethernet trailer included or others */
199 #if 0
200 pkt_trim(pkt, pkt_len(pkt) - min(pkt_len(pkt),
201 (ntohs(ip->h_tot_len) - ip->h_ihl * sizeof(uint32_t))));
202 #endif
203 pkt_set_dissector(pkt, &eth_lay3, ip->h_protocol);
206 struct protocol ipv4_ops = {
207 .key = 0x0800,
208 .print_full = ipv4,
209 .print_less = ipv4_less,