mod_print.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450
  1. /*
  2. * mod_print.c
  3. *
  4. * Copyright (c) 2001 Dug Song <dugsong@monkey.org>
  5. *
  6. * $Id$
  7. */
  8. #include "config.h"
  9. #include "mod.h"
  10. #include "pkt.h"
  11. #include <stdio.h>
  12. #include <stdlib.h>
  13. #include <string.h>
  14. #ifndef INET6_ADDRSTRLEN
  15. #define INET6_ADDRSTRLEN 46
  16. #endif
  17. #define EXTRACT_16BITS(p) ((uint16_t)ntohs(*(uint16_t *)(p)))
  18. #define EXTRACT_32BITS(p) ((uint32_t)ntohl(*(uint32_t *)(p)))
  19. /* XXX - _print_* routines adapted from tcpdump */
  20. static void
  21. print_icmp(u_char *p, _U_ int length)
  22. {
  23. struct ip_hdr *ip;
  24. struct icmp_hdr *icmp;
  25. ip = (struct ip_hdr *)p;
  26. icmp = (struct icmp_hdr *)(p + (ip->ip_hl * 4));
  27. /* XXX - truncation? */
  28. printf("%s > %s:", ip_ntoa(&ip->ip_src), ip_ntoa(&ip->ip_dst));
  29. printf(" icmp: type %d code %d", icmp->icmp_type, icmp->icmp_code);
  30. }
  31. static void
  32. print_icmp6(u_char *p, _U_ int length)
  33. {
  34. struct ip6_hdr *ip6;
  35. struct icmp_hdr *icmp;
  36. ip6 = (struct ip6_hdr *)p;
  37. icmp = (struct icmp_hdr *)(p + IP6_HDR_LEN);
  38. /* XXX - truncation? */
  39. printf("%s > %s:", ip6_ntoa(&ip6->ip6_src), ip6_ntoa(&ip6->ip6_dst));
  40. printf(" icmp: type %hhu code %hhu", icmp->icmp_type, icmp->icmp_code);
  41. }
  42. void
  43. print_tcp(int family, unsigned char *p, int length)
  44. {
  45. struct tcp_hdr *tcp;
  46. u_short sport, dport, win, urp;
  47. u_long seq, ack;
  48. int len, tcp_hl;
  49. register char ch;
  50. char src[INET6_ADDRSTRLEN], dst[INET6_ADDRSTRLEN];
  51. if (family == AF_INET6) {
  52. struct ip6_hdr *ip6 = (struct ip6_hdr *)p;
  53. tcp = (struct tcp_hdr *)(p + IP6_HDR_LEN);
  54. len = length;
  55. ip6_ntop(&ip6->ip6_src, src, sizeof(src));
  56. ip6_ntop(&ip6->ip6_dst, dst, sizeof(dst));
  57. } else {
  58. struct ip_hdr *ip;
  59. ip = (struct ip_hdr *)p;
  60. tcp = (struct tcp_hdr *)(p + (ip->ip_hl * 4));
  61. len = length - (ip->ip_hl * 4);
  62. ip_ntop(&ip->ip_src, src, sizeof(src));
  63. ip_ntop(&ip->ip_dst, dst, sizeof(dst));
  64. }
  65. if (len < TCP_HDR_LEN) {
  66. printf("truncated-tcp %d", len);
  67. return;
  68. }
  69. sport = ntohs(tcp->th_sport);
  70. dport = ntohs(tcp->th_dport);
  71. seq = ntohl(tcp->th_seq);
  72. ack = ntohl(tcp->th_ack);
  73. win = ntohs(tcp->th_win);
  74. urp = ntohs(tcp->th_urp);
  75. tcp_hl = tcp->th_off * 4;
  76. printf("%s.%d > %s.%d: ", src, sport, dst, dport);
  77. if (tcp->th_flags & (TH_SYN | TH_FIN | TH_RST | TH_PUSH)) {
  78. if (tcp->th_flags & TH_SYN)
  79. putchar('S');
  80. if (tcp->th_flags & TH_FIN)
  81. putchar('F');
  82. if (tcp->th_flags & TH_RST)
  83. putchar('R');
  84. if (tcp->th_flags & TH_PUSH)
  85. putchar('P');
  86. } else
  87. putchar('.');
  88. if (tcp_hl > len) {
  89. printf(" [bad hdr length]");
  90. return;
  91. }
  92. len -= tcp_hl;
  93. if (len > 0 || tcp->th_flags & (TH_SYN | TH_FIN | TH_RST))
  94. printf(" %lu:%lu(%d)", seq, seq + len, len);
  95. if (tcp->th_flags & TH_ACK)
  96. printf(" ack %lu", ack);
  97. printf(" win %d", win);
  98. if (tcp->th_flags & TH_URG)
  99. printf(" urg %d", urp);
  100. /* Handle options. */
  101. if ((tcp_hl -= TCP_HDR_LEN) > 0) {
  102. register const u_char *cp;
  103. register int i, opt, len, datalen;
  104. cp = (const u_char *)tcp + TCP_HDR_LEN;
  105. putchar(' ');
  106. ch = '<';
  107. while (tcp_hl > 0) {
  108. putchar(ch);
  109. opt = *cp++;
  110. if (TCP_OPT_TYPEONLY(opt)) {
  111. len = 1;
  112. } else {
  113. len = *cp++; /* total including type, len */
  114. if (len < 2 || len > tcp_hl)
  115. goto bad;
  116. --tcp_hl; /* account for length byte */
  117. }
  118. --tcp_hl; /* account for type byte */
  119. datalen = 0;
  120. /* Bail if "l" bytes of data are not left or were not captured */
  121. #define LENCHECK(l) \
  122. { \
  123. if ((l) > tcp_hl) \
  124. goto bad; \
  125. }
  126. switch (opt) {
  127. case TCP_OPT_MSS:
  128. printf("mss");
  129. datalen = 2;
  130. LENCHECK(datalen);
  131. printf(" %u", EXTRACT_16BITS(cp));
  132. break;
  133. case TCP_OPT_EOL:
  134. printf("eol");
  135. break;
  136. case TCP_OPT_NOP:
  137. printf("nop");
  138. break;
  139. case TCP_OPT_WSCALE:
  140. printf("wscale");
  141. datalen = 1;
  142. LENCHECK(datalen);
  143. printf(" %u", *cp);
  144. break;
  145. case TCP_OPT_SACKOK:
  146. printf("sackOK");
  147. if (len != 2)
  148. printf("[len %d]", len);
  149. break;
  150. case TCP_OPT_SACK:
  151. datalen = len - 2;
  152. if ((datalen % 8) != 0 || !(tcp->th_flags & TH_ACK)) {
  153. printf("malformed sack ");
  154. printf("[len %d] ", datalen);
  155. break;
  156. }
  157. printf("sack %d ", datalen / 8);
  158. break;
  159. case TCP_OPT_ECHO:
  160. printf("echo");
  161. datalen = 4;
  162. LENCHECK(datalen);
  163. printf(" %u", EXTRACT_32BITS(cp));
  164. break;
  165. case TCP_OPT_ECHOREPLY:
  166. printf("echoreply");
  167. datalen = 4;
  168. LENCHECK(datalen);
  169. printf(" %u", EXTRACT_32BITS(cp));
  170. break;
  171. case TCP_OPT_TIMESTAMP:
  172. printf("timestamp");
  173. datalen = 8;
  174. LENCHECK(4);
  175. printf(" %u", EXTRACT_32BITS(cp));
  176. LENCHECK(datalen);
  177. printf(" %u", EXTRACT_32BITS(cp + 4));
  178. break;
  179. case TCP_OPT_CC:
  180. printf("cc");
  181. datalen = 4;
  182. LENCHECK(datalen);
  183. printf(" %u", EXTRACT_32BITS(cp));
  184. break;
  185. case TCP_OPT_CCNEW:
  186. printf("ccnew");
  187. datalen = 4;
  188. LENCHECK(datalen);
  189. printf(" %u", EXTRACT_32BITS(cp));
  190. break;
  191. case TCP_OPT_CCECHO:
  192. printf("ccecho");
  193. datalen = 4;
  194. LENCHECK(datalen);
  195. printf(" %u", EXTRACT_32BITS(cp));
  196. break;
  197. default:
  198. printf("opt-%d:", opt);
  199. datalen = len - 2;
  200. for (i = 0; i < datalen; ++i) {
  201. LENCHECK(i);
  202. printf("%02x", cp[i]);
  203. }
  204. break;
  205. }
  206. /* Account for data printed */
  207. cp += datalen;
  208. tcp_hl -= datalen;
  209. /* Check specification against observed length */
  210. ++datalen; /* option octet */
  211. if (!TCP_OPT_TYPEONLY(opt))
  212. ++datalen; /* size octet */
  213. if (datalen != len)
  214. printf("[len %d]", len);
  215. ch = ',';
  216. if (opt == TCP_OPT_EOL)
  217. break;
  218. }
  219. putchar('>');
  220. }
  221. return;
  222. bad:
  223. fputs("[bad opt]", stdout);
  224. if (ch != '\0')
  225. putchar('>');
  226. return;
  227. }
  228. static void
  229. print_udp(int family, u_char *p, _U_ int length)
  230. {
  231. struct udp_hdr *udp;
  232. char src[INET6_ADDRSTRLEN], dst[INET6_ADDRSTRLEN];
  233. if (family == AF_INET6) {
  234. struct ip6_hdr *ip6 = (struct ip6_hdr *)p;
  235. udp = (struct udp_hdr *)(p + IP6_HDR_LEN);
  236. ip6_ntop(&ip6->ip6_src, src, sizeof(src));
  237. ip6_ntop(&ip6->ip6_dst, dst, sizeof(dst));
  238. } else {
  239. struct ip_hdr *ip;
  240. ip = (struct ip_hdr *)p;
  241. udp = (struct udp_hdr *)(p + (ip->ip_hl * 4));
  242. ip_ntop(&ip->ip_src, src, sizeof(src));
  243. ip_ntop(&ip->ip_dst, dst, sizeof(dst));
  244. }
  245. /* XXX - truncation? */
  246. printf("%s.%d > %s.%d:", src, ntohs(udp->uh_sport), dst, ntohs(udp->uh_dport));
  247. printf(" udp %d", ntohs(udp->uh_ulen) - UDP_HDR_LEN);
  248. }
  249. static void
  250. print_frag6(u_char *p, _U_ int length)
  251. {
  252. struct ip6_hdr *ip6;
  253. struct ip6_ext_hdr *ext;
  254. int off;
  255. ip6 = (struct ip6_hdr *)p;
  256. ext = (struct ip6_ext_hdr *)(p + IP6_HDR_LEN);
  257. off = htons(ext->ext_data.fragment.offlg & IP6_OFF_MASK);
  258. printf("%s > %s:", ip6_ntoa(&ip6->ip6_src), ip6_ntoa(&ip6->ip6_dst));
  259. printf(" fragment: next %hhu offset %d%s ident 0x%08x",
  260. ext->ext_nxt,
  261. off,
  262. (ext->ext_data.fragment.offlg & IP6_MORE_FRAG) ? " MF" : "",
  263. htonl(ext->ext_data.fragment.ident));
  264. }
  265. static void
  266. print_ip(u_char *p, int length)
  267. {
  268. struct ip_hdr *ip;
  269. int ip_off, ip_hl, ip_len;
  270. ip = (struct ip_hdr *)p;
  271. if (length < IP_HDR_LEN) {
  272. printf("truncated-ip %d", length);
  273. return;
  274. }
  275. ip_hl = ip->ip_hl * 4;
  276. ip_len = ntohs(ip->ip_len);
  277. if (length < ip_len) {
  278. printf("truncated-ip - %d bytes missing!", ip_len - length);
  279. return;
  280. }
  281. ip_off = ntohs(ip->ip_off);
  282. /* Handle first fragment. */
  283. if ((ip_off & IP_OFFMASK) == 0) {
  284. switch (ip->ip_p) {
  285. case IP_PROTO_TCP:
  286. print_tcp(AF_INET, p, ip_len);
  287. break;
  288. case IP_PROTO_UDP:
  289. print_udp(AF_INET, p, ip_len);
  290. break;
  291. case IP_PROTO_ICMP:
  292. print_icmp(p, ip_len);
  293. break;
  294. default:
  295. printf("%s > %s:", ip_ntoa(&ip->ip_src), ip_ntoa(&ip->ip_dst));
  296. printf(" ip-proto-%d %d", ip->ip_p, ip_len);
  297. break;
  298. }
  299. }
  300. /* Handle more frags. */
  301. if (ip_off & (IP_MF | IP_OFFMASK)) {
  302. if (ip_off & IP_OFFMASK)
  303. printf("%s > %s:", ip_ntoa(&ip->ip_src), ip_ntoa(&ip->ip_dst));
  304. printf(" (frag %d:%d@%d%s)",
  305. ntohs(ip->ip_id),
  306. ip_len - ip_hl,
  307. (ip_off & IP_OFFMASK) << 3,
  308. (ip_off & IP_MF) ? "+" : "");
  309. } else if (ip_off & IP_DF)
  310. printf(" (DF)");
  311. if (ip->ip_tos)
  312. printf(" [tos 0x%x]", ip->ip_tos);
  313. if (ip->ip_ttl <= 1)
  314. printf(" [ttl %d]", ip->ip_ttl);
  315. }
  316. static void
  317. print_ip6(u_char *p, int length)
  318. {
  319. struct ip6_hdr *ip6;
  320. int plen;
  321. ip6 = (struct ip6_hdr *)p;
  322. if (length < IP6_HDR_LEN) {
  323. printf("truncated-ip6 %d", length);
  324. return;
  325. }
  326. plen = htons(ip6->ip6_plen);
  327. switch (ip6->ip6_nxt) {
  328. case IP_PROTO_TCP:
  329. print_tcp(AF_INET6, p, plen);
  330. break;
  331. case IP_PROTO_UDP:
  332. print_udp(AF_INET6, p, plen);
  333. break;
  334. case IP_PROTO_ICMPV6:
  335. print_icmp6(p, plen);
  336. break;
  337. case IP_PROTO_FRAGMENT:
  338. print_frag6(p, plen);
  339. break;
  340. default:
  341. printf("%s > %s:", ip6_ntoa(&ip6->ip6_src), ip6_ntoa(&ip6->ip6_dst));
  342. printf(" ip-proto-%hhu ttl %hhu payload len %d", ip6->ip6_nxt, ip6->ip6_hlim, plen);
  343. break;
  344. }
  345. if (ip6->ip6_hlim <= 1)
  346. printf(" [ttl %d]", ip6->ip6_hlim);
  347. }
  348. static void
  349. print_eth(struct eth_hdr *e, int length)
  350. {
  351. char d[20], s[20];
  352. eth_ntop(&e->eth_dst, &d[0], sizeof(d));
  353. eth_ntop(&e->eth_src, &s[0], sizeof(s));
  354. printf("%s > %s type 0x%04hx length %d", d, s, htons(e->eth_type), length);
  355. }
  356. static char *
  357. timerntoa(struct timeval *tv)
  358. {
  359. static char buf[128];
  360. uint64_t usec;
  361. usec = (tv->tv_sec * 1000000) + tv->tv_usec;
  362. snprintf(buf, sizeof(buf), "%d.%03d ms", (int)(usec / 1000), (int)(usec % 1000));
  363. return (buf);
  364. }
  365. int
  366. print_apply(_U_ void *d, struct pktq *pktq)
  367. {
  368. struct pkt *pkt;
  369. TAILQ_FOREACH(pkt, pktq, pkt_next)
  370. {
  371. uint16_t eth_type = htons(pkt->pkt_eth->eth_type);
  372. if (eth_type == ETH_TYPE_IP)
  373. print_ip(pkt->pkt_eth_data, pkt->pkt_end - pkt->pkt_eth_data);
  374. else if (eth_type == ETH_TYPE_IPV6)
  375. print_ip6(pkt->pkt_eth_data, pkt->pkt_end - pkt->pkt_eth_data);
  376. else
  377. print_eth(pkt->pkt_eth, pkt->pkt_end - pkt->pkt_data);
  378. if (timerisset(&pkt->pkt_ts))
  379. printf(" [delay %s]", timerntoa(&pkt->pkt_ts));
  380. printf("\n");
  381. }
  382. return (0);
  383. }
  384. struct mod mod_print = {
  385. "print", /* name */
  386. "print", /* usage */
  387. NULL, /* init */
  388. print_apply, /* apply */
  389. NULL /* close */
  390. };