mod_print.c 12 KB

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