pkt.c 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312
  1. /*
  2. * pkt.c
  3. *
  4. * Copyright (c) 2001 Dug Song <dugsong@monkey.org>
  5. *
  6. * $Id: pkt.c 2303 2009-05-06 18:48:20Z aturner $
  7. */
  8. #include "config.h"
  9. #include <sys/types.h>
  10. #include <stdio.h>
  11. #include <stdlib.h>
  12. #include <string.h>
  13. #include "bget.h"
  14. #include "pkt.h"
  15. void
  16. pkt_init(int size)
  17. {
  18. bectl(NULL, malloc, free, sizeof(struct pkt) * size);
  19. }
  20. struct pkt *
  21. pkt_new(void)
  22. {
  23. struct pkt *pkt;
  24. if ((pkt = bget(sizeof(*pkt))) == NULL)
  25. return (NULL);
  26. timerclear(&pkt->pkt_ts);
  27. // memset(&pkt->pkt_ev, 0, sizeof(pkt->pkt_ev));
  28. pkt->pkt_data = pkt->pkt_buf + PKT_BUF_ALIGN;
  29. pkt->pkt_eth = (struct eth_hdr *)pkt->pkt_data;
  30. pkt->pkt_eth_data = pkt->pkt_data + ETH_HDR_LEN;
  31. pkt->pkt_ip_data = pkt->pkt_data + ETH_HDR_LEN + IP_HDR_LEN;
  32. pkt->pkt_tcp_data = NULL;
  33. pkt->pkt_end = pkt->pkt_ip_data;
  34. return (pkt);
  35. }
  36. struct pkt *
  37. pkt_dup(struct pkt *pkt)
  38. {
  39. struct pkt *new;
  40. off_t off;
  41. if ((new = bget(sizeof(*new))) == NULL)
  42. return (NULL);
  43. off = new->pkt_buf - pkt->pkt_buf;
  44. new->pkt_ts = pkt->pkt_ts;
  45. // memset(&new->pkt_ev, 0, sizeof(new->pkt_ev));
  46. new->pkt_data = pkt->pkt_data + off;
  47. new->pkt_eth = (pkt->pkt_eth != NULL) ?
  48. (struct eth_hdr *)new->pkt_data : NULL;
  49. new->pkt_eth_data = (pkt->pkt_eth_data != NULL) ?
  50. pkt->pkt_eth_data + off : NULL;
  51. new->pkt_ip_data = (pkt->pkt_ip_data != NULL) ?
  52. pkt->pkt_ip_data + off : NULL;
  53. new->pkt_tcp_data = (pkt->pkt_tcp_data != NULL) ?
  54. pkt->pkt_tcp_data + off : NULL;
  55. memcpy(new->pkt_data, pkt->pkt_data, pkt->pkt_end - pkt->pkt_data);
  56. new->pkt_end = pkt->pkt_end + off;
  57. return (new);
  58. }
  59. #define IP6_IS_EXT(n) \
  60. ((n) == IP_PROTO_HOPOPTS || (n) == IP_PROTO_DSTOPTS || \
  61. (n) == IP_PROTO_ROUTING || (n) == IP_PROTO_FRAGMENT)
  62. void
  63. pkt_decorate(struct pkt *pkt)
  64. {
  65. u_char *p;
  66. uint16_t eth_type;
  67. int hl, len, off;
  68. uint8_t next_hdr;
  69. struct ip6_ext_hdr *ext;
  70. pkt->pkt_data = pkt->pkt_buf + PKT_BUF_ALIGN;
  71. pkt->pkt_eth = NULL;
  72. pkt->pkt_ip = NULL;
  73. pkt->pkt_ip_data = NULL;
  74. pkt->pkt_tcp_data = NULL;
  75. p = pkt->pkt_data;
  76. if (p + ETH_HDR_LEN > pkt->pkt_end)
  77. return;
  78. pkt->pkt_eth = (struct eth_hdr *)p;
  79. p += ETH_HDR_LEN;
  80. eth_type = htons(pkt->pkt_eth->eth_type);
  81. if (eth_type == ETH_TYPE_IP) {
  82. if (p + IP_HDR_LEN > pkt->pkt_end)
  83. return;
  84. pkt->pkt_eth_data = p;
  85. /* If IP header length is longer than packet length, stop. */
  86. hl = pkt->pkt_ip->ip_hl << 2;
  87. if (p + hl > pkt->pkt_end) {
  88. pkt->pkt_ip = NULL;
  89. return;
  90. }
  91. /* If IP length is longer than packet length, stop. */
  92. len = ntohs(pkt->pkt_ip->ip_len);
  93. if (p + len > pkt->pkt_end)
  94. return;
  95. /* If IP fragment, stop. */
  96. off = ntohs(pkt->pkt_ip->ip_off);
  97. if ((off & IP_OFFMASK) != 0 || (off & IP_MF) != 0)
  98. return;
  99. pkt->pkt_end = p + len;
  100. p += hl;
  101. next_hdr = pkt->pkt_ip->ip_p;
  102. } else if (eth_type == ETH_TYPE_IPV6) {
  103. if (p + IP6_HDR_LEN > pkt->pkt_end)
  104. return;
  105. pkt->pkt_eth_data = p;
  106. p += IP6_HDR_LEN;
  107. next_hdr = pkt->pkt_ip6->ip6_nxt;
  108. for (; IP6_IS_EXT(next_hdr); p += (ext->ext_len + 1) << 3) {
  109. if (p > pkt->pkt_end)
  110. return;
  111. ext = (struct ip6_ext_hdr *)p;
  112. next_hdr = ext->ext_nxt;
  113. }
  114. } else {
  115. return;
  116. }
  117. /* If transport layer header is longer than packet length, stop. */
  118. switch (next_hdr) {
  119. case IP_PROTO_ICMP:
  120. case IP_PROTO_ICMPV6:
  121. hl = ICMP_HDR_LEN;
  122. break;
  123. case IP_PROTO_TCP:
  124. if (p + TCP_HDR_LEN > pkt->pkt_end)
  125. return;
  126. hl = ((struct tcp_hdr *)p)->th_off << 2;
  127. break;
  128. case IP_PROTO_UDP:
  129. hl = UDP_HDR_LEN;
  130. break;
  131. default:
  132. return;
  133. }
  134. if (p + hl > pkt->pkt_end)
  135. return;
  136. pkt->pkt_ip_data = p;
  137. p += hl;
  138. /* Check for transport layer data. */
  139. switch (next_hdr) {
  140. case IP_PROTO_ICMP:
  141. pkt->pkt_icmp_msg = (union icmp_msg *)p;
  142. switch (pkt->pkt_icmp->icmp_type) {
  143. case ICMP_ECHO:
  144. case ICMP_ECHOREPLY:
  145. hl = sizeof(pkt->pkt_icmp_msg->echo);
  146. break;
  147. case ICMP_UNREACH:
  148. if (pkt->pkt_icmp->icmp_code == ICMP_UNREACH_NEEDFRAG)
  149. hl = sizeof(pkt->pkt_icmp_msg->needfrag);
  150. else
  151. hl = sizeof(pkt->pkt_icmp_msg->unreach);
  152. break;
  153. case ICMP_SRCQUENCH:
  154. case ICMP_REDIRECT:
  155. case ICMP_TIMEXCEED:
  156. case ICMP_PARAMPROB:
  157. hl = sizeof(pkt->pkt_icmp_msg->srcquench);
  158. break;
  159. case ICMP_RTRADVERT:
  160. hl = sizeof(pkt->pkt_icmp_msg->rtradvert);
  161. break;
  162. case ICMP_RTRSOLICIT:
  163. hl = sizeof(pkt->pkt_icmp_msg->rtrsolicit);
  164. break;
  165. case ICMP_TSTAMP:
  166. case ICMP_TSTAMPREPLY:
  167. hl = sizeof(pkt->pkt_icmp_msg->tstamp);
  168. break;
  169. case ICMP_INFO:
  170. case ICMP_INFOREPLY:
  171. case ICMP_DNS:
  172. hl = sizeof(pkt->pkt_icmp_msg->info);
  173. break;
  174. case ICMP_MASK:
  175. case ICMP_MASKREPLY:
  176. hl = sizeof(pkt->pkt_icmp_msg->mask);
  177. break;
  178. case ICMP_DNSREPLY:
  179. hl = sizeof(pkt->pkt_icmp_msg->dnsreply);
  180. break;
  181. default:
  182. hl = pkt->pkt_end - p + 1;
  183. break;
  184. }
  185. if (p + hl > pkt->pkt_end)
  186. pkt->pkt_icmp_msg = NULL;
  187. break;
  188. case IP_PROTO_ICMPV6:
  189. pkt->pkt_icmp_msg = (union icmp_msg *)p;
  190. break;
  191. case IP_PROTO_TCP:
  192. if (p < pkt->pkt_end)
  193. pkt->pkt_tcp_data = p;
  194. break;
  195. case IP_PROTO_UDP:
  196. if (pkt->pkt_ip_data + ntohs(pkt->pkt_udp->uh_ulen) <=
  197. pkt->pkt_end)
  198. pkt->pkt_udp_data = p;
  199. break;
  200. }
  201. }
  202. void
  203. pkt_free(struct pkt *pkt)
  204. {
  205. brel(pkt);
  206. }
  207. void
  208. pktq_reverse(struct pktq *pktq)
  209. {
  210. struct pktq tmpq;
  211. struct pkt *pkt, *next;
  212. TAILQ_INIT(&tmpq);
  213. for (pkt = TAILQ_FIRST(pktq); pkt != TAILQ_END(pktq); pkt = next) {
  214. next = TAILQ_NEXT(pkt, pkt_next);
  215. TAILQ_INSERT_HEAD(&tmpq, pkt, pkt_next);
  216. }
  217. *pktq = tmpq;
  218. }
  219. void
  220. pktq_shuffle(rand_t *r, struct pktq *pktq)
  221. {
  222. static struct pkt **pvbase;
  223. static int pvlen;
  224. struct pkt *pkt;
  225. int i;
  226. i = 0;
  227. TAILQ_FOREACH(pkt, pktq, pkt_next) {
  228. i++;
  229. }
  230. if (i > pvlen) {
  231. pvlen = i;
  232. if (pvbase == NULL)
  233. pvbase = malloc(sizeof(pkt) * pvlen);
  234. else
  235. pvbase = realloc(pvbase, sizeof(pkt) * pvlen);
  236. }
  237. i = 0;
  238. TAILQ_FOREACH(pkt, pktq, pkt_next) {
  239. pvbase[i++] = pkt;
  240. }
  241. TAILQ_INIT(pktq);
  242. rand_shuffle(r, pvbase, i, sizeof(pkt));
  243. while (--i >= 0) {
  244. TAILQ_INSERT_TAIL(pktq, pvbase[i], pkt_next);
  245. }
  246. }
  247. struct pkt *
  248. pktq_random(rand_t *r, struct pktq *pktq)
  249. {
  250. struct pkt *pkt;
  251. int i;
  252. i = 0;
  253. TAILQ_FOREACH(pkt, pktq, pkt_next) {
  254. i++;
  255. }
  256. i = rand_uint32(r) % (i - 1);
  257. pkt = TAILQ_FIRST(pktq);
  258. while (--i >= 0) {
  259. pkt = TAILQ_NEXT(pkt, pkt_next);
  260. }
  261. return (pkt);
  262. }