netsniff-ng, nlmsg: Dissect rtnl link type messages
[netsniff-ng.git] / proto_nlmsg.c
blob89b48b22af0b25af2f16e2b777b5acbf24762582
1 /*
2 * netsniff-ng - the packet sniffing beast
3 * Copyright 2014 Tobias Klauser.
4 * Subject to the GPL, version 2.
5 */
7 #include <stdio.h>
8 #include <unistd.h>
9 #include <limits.h>
10 #include <libgen.h>
11 #include <netlink/msg.h>
12 #include <netlink/route/link.h>
13 #include <linux/if_arp.h>
14 #include <arpa/inet.h>
16 #include "pkt_buff.h"
17 #include "proto.h"
18 #include "protos.h"
20 static const char *nlmsg_family2str(uint16_t family)
22 switch (family) {
23 case NETLINK_ROUTE: return "routing";
24 case NETLINK_UNUSED: return "unused";
25 case NETLINK_USERSOCK: return "user-mode socket";
26 case NETLINK_FIREWALL: return "unused, formerly ip_queue";
27 /* NETLINK_INET_DIAG was renamed to NETLINK_SOCK_DIAG in Linux kernel 3.10 */
28 #if defined(NETLINK_SOCK_DIAG)
29 case NETLINK_SOCK_DIAG: return "socket monitoring";
30 #elif defined(NETLINK_INET_DIAG)
31 case NETLINK_INET_DIAG: return "INET socket monitoring";
32 #endif
33 case NETLINK_NFLOG: return "netfilter ULOG";
34 case NETLINK_XFRM: return "IPsec";
35 case NETLINK_SELINUX: return "SELinux event notification";
36 case NETLINK_ISCSI: return "Open-iSCSI";
37 case NETLINK_AUDIT: return "auditing";
38 case NETLINK_FIB_LOOKUP: return "FIB lookup";
39 case NETLINK_CONNECTOR: return "Kernel connector";
40 case NETLINK_NETFILTER: return "Netfilter";
41 case NETLINK_IP6_FW: return "unused, formerly ip6_queue";
42 case NETLINK_DNRTMSG: return "DECnet routing";
43 case NETLINK_KOBJECT_UEVENT: return "Kernel messages";
44 case NETLINK_GENERIC: return "Generic";
45 case NETLINK_SCSITRANSPORT: return "SCSI transports";
46 case NETLINK_ECRYPTFS: return "ecryptfs";
47 case NETLINK_RDMA: return "RDMA";
48 case NETLINK_CRYPTO: return "Crypto layer";
49 default: return "Unknown";
53 static const char *nlmsg_rtnl_type2str(uint16_t type)
55 switch (type) {
56 case RTM_NEWLINK: return "new link";
57 case RTM_DELLINK: return "del link";
58 case RTM_GETLINK: return "get link";
59 case RTM_SETLINK: return "set link";
61 case RTM_NEWADDR: return "new addr";
62 case RTM_DELADDR: return "del addr";
63 case RTM_GETADDR: return "get addr";
65 case RTM_NEWROUTE: return "new route";
66 case RTM_DELROUTE: return "del route";
67 case RTM_GETROUTE: return "get route";
69 case RTM_NEWNEIGH: return "new neigh";
70 case RTM_DELNEIGH: return "del neigh";
71 case RTM_GETNEIGH: return "get neigh";
73 case RTM_NEWRULE: return "new rule";
74 case RTM_DELRULE: return "del rule";
75 case RTM_GETRULE: return "get rule";
77 case RTM_NEWQDISC: return "new tc qdisc";
78 case RTM_DELQDISC: return "del tc qdisc";
79 case RTM_GETQDISC: return "get tc qdisc";
81 case RTM_NEWTCLASS: return "new tc class";
82 case RTM_DELTCLASS: return "del tc class";
83 case RTM_GETTCLASS: return "get tc class";
85 case RTM_NEWTFILTER: return "new tc filter";
86 case RTM_DELTFILTER: return "del tc filter";
87 case RTM_GETTFILTER: return "get tc filter";
89 case RTM_NEWACTION: return "new tc action";
90 case RTM_DELACTION: return "del tc action";
91 case RTM_GETACTION: return "get tc action";
93 case RTM_NEWPREFIX: return "new prefix";
95 case RTM_GETMULTICAST: return "get mcast addr";
97 case RTM_GETANYCAST: return "get anycast addr";
99 case RTM_NEWNEIGHTBL: return "new neigh table";
100 case RTM_GETNEIGHTBL: return "get neigh table";
101 case RTM_SETNEIGHTBL: return "set neigh table";
103 case RTM_NEWNDUSEROPT: return "new ndisc user option";
105 case RTM_NEWADDRLABEL: return "new addr label";
106 case RTM_DELADDRLABEL: return "del addr label";
107 case RTM_GETADDRLABEL: return "get addr label";
109 case RTM_GETDCB: return "get data-center-bridge";
110 case RTM_SETDCB: return "set data-center-bridge";
112 #if defined(RTM_NEWNETCONF)
113 case RTM_NEWNETCONF: return "new netconf";
114 case RTM_GETNETCONF: return "get netconf";
115 #endif
117 #if defined(RTM_NEWMDB)
118 case RTM_NEWMDB: return "new bridge mdb";
119 case RTM_DELMDB: return "del bridge mdb";
120 case RTM_GETMDB: return "get bridge mdb";
121 #endif
122 default: return NULL;
126 static char *if_type2str(uint16_t type)
128 switch (type) {
129 case ARPHRD_ETHER: return "ether";
130 case ARPHRD_EETHER: return "eether";
131 case ARPHRD_AX25: return "ax25";
132 case ARPHRD_PRONET: return "pronet";
133 case ARPHRD_CHAOS: return "chaos";
134 case ARPHRD_IEEE802: return "ieee802";
135 case ARPHRD_ARCNET: return "arcnet";
136 case ARPHRD_APPLETLK: return "appletlk";
137 case ARPHRD_DLCI: return "dlci";
138 case ARPHRD_ATM: return "atm";
139 case ARPHRD_METRICOM: return "metricom";
140 case ARPHRD_IEEE1394: return "ieee1394";
141 case ARPHRD_INFINIBAND: return "infiniband";
142 case ARPHRD_SLIP: return "slip";
143 case ARPHRD_CSLIP: return "cslip";
144 case ARPHRD_SLIP6: return "slip6";
145 case ARPHRD_CSLIP6: return "cslip6";
146 case ARPHRD_RSRVD: return "RSRVD";
147 case ARPHRD_ADAPT: return "adapt";
148 case ARPHRD_ROSE: return "rose";
149 case ARPHRD_X25: return "x25";
150 case ARPHRD_HWX25: return "hwx25";
151 case ARPHRD_CAN: return "can";
152 case ARPHRD_PPP: return "ppp";
153 case ARPHRD_HDLC: return "hdlc";
154 case ARPHRD_LAPB: return "lapb";
155 case ARPHRD_DDCMP: return "ddcmp";
156 case ARPHRD_RAWHDLC: return "rawhdlc";
157 case ARPHRD_TUNNEL: return "tunnel";
158 case ARPHRD_TUNNEL6: return "tunnel6";
159 case ARPHRD_FRAD: return "frad";
160 case ARPHRD_SKIP: return "skip";
161 case ARPHRD_LOOPBACK: return "loopback";
162 case ARPHRD_LOCALTLK: return "localtlk";
163 case ARPHRD_FDDI: return "fddi";
164 case ARPHRD_BIF: return "bif";
165 case ARPHRD_SIT: return "sit";
166 case ARPHRD_IPDDP: return "ipddp";
167 case ARPHRD_IPGRE: return "ipgre";
168 case ARPHRD_PIMREG: return "pimreg";
169 case ARPHRD_HIPPI: return "hippi";
170 case ARPHRD_ASH: return "ash";
171 case ARPHRD_ECONET: return "econet";
172 case ARPHRD_IRDA: return "irda";
173 case ARPHRD_FCPP: return "fcpp";
174 case ARPHRD_FCAL: return "fcal";
175 case ARPHRD_FCPL: return "fcpl";
176 case ARPHRD_FCFABRIC: return "fcfb0";
177 case ARPHRD_FCFABRIC + 1: return "fcfb1";
178 case ARPHRD_FCFABRIC + 2: return "fcfb2";
179 case ARPHRD_FCFABRIC + 3: return "fcfb3";
180 case ARPHRD_FCFABRIC + 4: return "fcfb4";
181 case ARPHRD_FCFABRIC + 5: return "fcfb5";
182 case ARPHRD_FCFABRIC + 6: return "fcfb6";
183 case ARPHRD_FCFABRIC + 7: return "fcfb7";
184 case ARPHRD_FCFABRIC + 8: return "fcfb8";
185 case ARPHRD_FCFABRIC + 9: return "fcfb9";
186 case ARPHRD_FCFABRIC + 10: return "fcfb10";
187 case ARPHRD_FCFABRIC + 11: return "fcfb11";
188 case ARPHRD_FCFABRIC + 12: return "fcfb12";
189 case ARPHRD_IEEE802_TR: return "ieee802_tr";
190 case ARPHRD_IEEE80211: return "ieee80211";
191 case ARPHRD_IEEE80211_PRISM: return "ieee80211_prism";
192 case ARPHRD_IEEE80211_RADIOTAP: return "ieee80211_radiotap";
193 case ARPHRD_IEEE802154: return "ieee802154";
194 case ARPHRD_PHONET: return "phonet";
195 case ARPHRD_PHONET_PIPE: return "phonet_pipe";
196 case ARPHRD_CAIF: return "caif";
197 case ARPHRD_IP6GRE: return "ip6gre";
198 case ARPHRD_NETLINK: return "netlink";
199 case ARPHRD_NONE: return "none";
200 case ARPHRD_VOID: return "void";
202 default: return "Unknown";
206 /* Taken from iproute2 */
207 static const char *ll_addr_n2a(const unsigned char *addr, int alen, int type,
208 char *buf, int blen)
210 int i;
211 int l;
213 if (alen == 4 &&
214 (type == ARPHRD_TUNNEL || type == ARPHRD_SIT || type == ARPHRD_IPGRE)) {
215 return inet_ntop(AF_INET, addr, buf, blen);
217 if (alen == 16 && type == ARPHRD_TUNNEL6) {
218 return inet_ntop(AF_INET6, addr, buf, blen);
220 l = 0;
221 for (i=0; i<alen; i++) {
222 if (i==0) {
223 snprintf(buf+l, blen, "%02x", addr[i]);
224 blen -= 2;
225 l += 2;
226 } else {
227 snprintf(buf+l, blen, ":%02x", addr[i]);
228 blen -= 3;
229 l += 3;
232 return buf;
235 static char *nlmsg_type2str(uint16_t proto, uint16_t type, char *buf, int len)
237 if (proto == NETLINK_ROUTE && type < RTM_MAX) {
238 const char *name = nlmsg_rtnl_type2str(type);
239 if (name) {
240 strncpy(buf, name, len);
241 return buf;
245 return nl_nlmsgtype2str(type, buf, len);
248 static void rtnl_print_ifinfo(struct nlmsghdr *hdr)
250 struct ifinfomsg *ifi = NLMSG_DATA(hdr);
251 struct rtattr *attr = IFLA_RTA(ifi);
252 uint32_t attrs_len = IFLA_PAYLOAD(hdr);
253 char flags[256];
254 char if_addr[64] = {};
255 char *af_link = "Unknown";
257 if (ifi->ifi_family == AF_UNSPEC)
258 af_link = "unspec";
259 else if (ifi->ifi_family == AF_BRIDGE)
260 af_link = "bridge";
262 tprintf(" [ Link Family %d (%s%s%s)", ifi->ifi_family,
263 colorize_start(bold), af_link, colorize_end());
264 tprintf(", Type %d (%s%s%s)", ifi->ifi_type,
265 colorize_start(bold),
266 if_type2str(ifi->ifi_type),
267 colorize_end());
268 tprintf(", Index %d", ifi->ifi_index);
269 tprintf(", Flags 0x%x (%s%s%s)", ifi->ifi_flags,
270 colorize_start(bold),
271 rtnl_link_flags2str(ifi->ifi_flags, flags,
272 sizeof(flags)),
273 colorize_end());
274 tprintf(", Change 0x%x (%s%s%s) ]\n", ifi->ifi_change,
275 colorize_start(bold),
276 rtnl_link_flags2str(ifi->ifi_change, flags,
277 sizeof(flags)),
278 colorize_end());
280 for (; RTA_OK(attr, attrs_len); attr = RTA_NEXT(attr, attrs_len)) {
281 switch (attr->rta_type) {
282 case IFLA_ADDRESS:
283 tprintf("\tA: Address %s\n",
284 ll_addr_n2a(RTA_DATA(attr),
285 RTA_PAYLOAD(attr),
286 ifi->ifi_type, if_addr,
287 sizeof(if_addr)));
288 break;
289 case IFLA_BROADCAST:
290 tprintf("\tA: Broadcast %s\n",
291 ll_addr_n2a(RTA_DATA(attr),
292 RTA_PAYLOAD(attr),
293 ifi->ifi_type, if_addr,
294 sizeof(if_addr)));
295 break;
296 case IFLA_IFNAME:
297 tprintf("\tA: Name %s%s%s\n",
298 colorize_start(bold),
299 (char *)(RTA_DATA(attr)),
300 colorize_end());
301 break;
302 case IFLA_MTU:
303 tprintf("\tA: MTU %d\n", *(int *)(RTA_DATA(attr)));
304 break;
305 case IFLA_LINK:
306 tprintf("\tA: Link %d\n", *(int *)(RTA_DATA(attr)));
307 break;
308 case IFLA_QDISC:
309 tprintf("\tA: QDisc %s\n", (char *)(RTA_DATA(attr)));
310 break;
311 case IFLA_OPERSTATE:
313 uint8_t st = *(uint8_t *)(RTA_DATA(attr));
314 char states[256];
316 tprintf("\tA: Operation state 0x%x (%s%s%s)\n",
318 colorize_start(bold),
319 rtnl_link_operstate2str(st,
320 states, sizeof(states)),
321 colorize_end());
323 break;
324 case IFLA_LINKMODE:
326 uint8_t mode = *(uint8_t *)(RTA_DATA(attr));
327 char str[32];
329 tprintf("\tA: Mode 0x%x (%s%s%s)\n", mode,
330 colorize_start(bold),
331 rtnl_link_mode2str(mode, str,
332 sizeof(str)),
333 colorize_end());
335 break;
336 case IFLA_GROUP:
337 tprintf("\tA: Group %d\n", *(int *)(RTA_DATA(attr)));
338 break;
339 case IFLA_TXQLEN:
340 tprintf("\tA: Tx queue len %d\n",
341 *(int *)(RTA_DATA(attr)));
342 break;
343 case IFLA_NET_NS_PID:
344 tprintf("\tA: Network namespace pid %d\n",
345 *(int *)(RTA_DATA(attr)));
346 break;
347 case IFLA_NET_NS_FD:
348 tprintf("\tA: Network namespace fd %d\n",
349 *(int *)(RTA_DATA(attr)));
350 break;
355 static void rtnl_msg_print(struct nlmsghdr *hdr)
357 switch (hdr->nlmsg_type) {
358 case RTM_NEWLINK:
359 case RTM_DELLINK:
360 case RTM_GETLINK:
361 case RTM_SETLINK:
362 rtnl_print_ifinfo(hdr);
366 static void nlmsg_print(uint16_t family, struct nlmsghdr *hdr)
368 char type[32];
369 char flags[128];
370 char procname[PATH_MAX];
372 /* Look up the process name if message is not coming from the kernel.
374 * Note that the port id is not necessarily equal to the PID of the
375 * receiving process (e.g. if the application is multithreaded or using
376 * multiple sockets). In these cases we're not able to find a matching
377 * PID and the information will not be printed.
379 if (hdr->nlmsg_pid != 0) {
380 char path[1024];
381 int ret;
383 snprintf(path, sizeof(path), "/proc/%u/exe", hdr->nlmsg_pid);
384 ret = readlink(path, procname, sizeof(procname) - 1);
385 if (ret < 0)
386 ret = 0;
387 procname[ret] = '\0';
388 } else
389 snprintf(procname, sizeof(procname), "kernel");
391 tprintf(" [ NLMSG ");
392 tprintf("Family %d (%s%s%s), ", family,
393 colorize_start(bold),
394 nlmsg_family2str(family),
395 colorize_end());
396 tprintf("Len %u, ", hdr->nlmsg_len);
397 tprintf("Type 0x%.4x (%s%s%s), ", hdr->nlmsg_type,
398 colorize_start(bold),
399 nlmsg_type2str(family, hdr->nlmsg_type, type, sizeof(type)),
400 colorize_end());
401 tprintf("Flags 0x%.4x (%s%s%s), ", hdr->nlmsg_flags,
402 colorize_start(bold),
403 nl_nlmsg_flags2str(hdr->nlmsg_flags, flags, sizeof(flags)),
404 colorize_end());
405 tprintf("Seq-Nr %u, ", hdr->nlmsg_seq);
406 tprintf("PID %u", hdr->nlmsg_pid);
407 if (procname[0])
408 tprintf(" (%s%s%s)", colorize_start(bold), basename(procname),
409 colorize_end());
410 tprintf(" ]\n");
412 if (family == NETLINK_ROUTE)
413 rtnl_msg_print(hdr);
416 static void nlmsg(struct pkt_buff *pkt)
418 struct nlmsghdr *hdr = (struct nlmsghdr *) pkt_pull(pkt, sizeof(*hdr));
420 while (hdr) {
421 nlmsg_print(ntohs(pkt->proto), hdr);
423 if (!pkt_pull(pkt, NLMSG_PAYLOAD(hdr, 0)))
424 break;
426 hdr = (struct nlmsghdr *) pkt_pull(pkt, sizeof(*hdr));
430 static void nlmsg_less(struct pkt_buff *pkt)
432 struct nlmsghdr *hdr = (struct nlmsghdr *) pkt_pull(pkt, sizeof(*hdr));
433 uint16_t family = ntohs(pkt->proto);
434 char type[32];
436 if (hdr == NULL)
437 return;
439 tprintf(" NLMSG Family %d (%s%s%s), ", family,
440 colorize_start(bold),
441 nlmsg_family2str(family),
442 colorize_end());
443 tprintf("Type %u (%s%s%s)", hdr->nlmsg_type,
444 colorize_start(bold),
445 nlmsg_type2str(family, hdr->nlmsg_type, type, sizeof(type)),
446 colorize_end());
449 struct protocol nlmsg_ops = {
450 .print_full = nlmsg,
451 .print_less = nlmsg_less,