ipaux.c 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368
  1. #include "u.h"
  2. #include "../port/lib.h"
  3. #include "mem.h"
  4. #include "dat.h"
  5. #include "fns.h"
  6. #include "../port/error.h"
  7. #include "ip.h"
  8. #include "ipv6.h"
  9. char *v6hdrtypes[Maxhdrtype] =
  10. {
  11. [HBH] "HopbyHop",
  12. [ICMP] "ICMP",
  13. [IGMP] "IGMP",
  14. [GGP] "GGP",
  15. [IPINIP] "IP",
  16. [ST] "ST",
  17. [TCP] "TCP",
  18. [UDP] "UDP",
  19. [ISO_TP4] "ISO_TP4",
  20. [RH] "Routinghdr",
  21. [FH] "Fraghdr",
  22. [IDRP] "IDRP",
  23. [RSVP] "RSVP",
  24. [AH] "Authhdr",
  25. [ESP] "ESP",
  26. [ICMPv6] "ICMPv6",
  27. [NNH] "Nonexthdr",
  28. [ISO_IP] "ISO_IP",
  29. [IGRP] "IGRP",
  30. [OSPF] "OSPF",
  31. };
  32. /*
  33. * well known IPv6 addresses
  34. */
  35. uchar v6Unspecified[IPaddrlen] = {
  36. 0, 0, 0, 0,
  37. 0, 0, 0, 0,
  38. 0, 0, 0, 0,
  39. 0, 0, 0, 0
  40. };
  41. uchar v6loopback[IPaddrlen] = {
  42. 0, 0, 0, 0,
  43. 0, 0, 0, 0,
  44. 0, 0, 0, 0,
  45. 0, 0, 0, 0x01
  46. };
  47. uchar v6linklocal[IPaddrlen] = {
  48. 0xfe, 0x80, 0, 0,
  49. 0, 0, 0, 0,
  50. 0, 0, 0, 0,
  51. 0, 0, 0, 0
  52. };
  53. uchar v6linklocalmask[IPaddrlen] = {
  54. 0xff, 0xff, 0xff, 0xff,
  55. 0xff, 0xff, 0xff, 0xff,
  56. 0, 0, 0, 0,
  57. 0, 0, 0, 0
  58. };
  59. int v6llpreflen = 8; /* link-local prefix length in bytes */
  60. uchar v6multicast[IPaddrlen] = {
  61. 0xff, 0, 0, 0,
  62. 0, 0, 0, 0,
  63. 0, 0, 0, 0,
  64. 0, 0, 0, 0
  65. };
  66. uchar v6multicastmask[IPaddrlen] = {
  67. 0xff, 0, 0, 0,
  68. 0, 0, 0, 0,
  69. 0, 0, 0, 0,
  70. 0, 0, 0, 0
  71. };
  72. int v6mcpreflen = 1; /* multicast prefix length */
  73. uchar v6allnodesN[IPaddrlen] = {
  74. 0xff, 0x01, 0, 0,
  75. 0, 0, 0, 0,
  76. 0, 0, 0, 0,
  77. 0, 0, 0, 0x01
  78. };
  79. uchar v6allroutersN[IPaddrlen] = {
  80. 0xff, 0x01, 0, 0,
  81. 0, 0, 0, 0,
  82. 0, 0, 0, 0,
  83. 0, 0, 0, 0x02
  84. };
  85. uchar v6allnodesNmask[IPaddrlen] = {
  86. 0xff, 0xff, 0, 0,
  87. 0, 0, 0, 0,
  88. 0, 0, 0, 0,
  89. 0, 0, 0, 0
  90. };
  91. int v6aNpreflen = 2; /* all nodes (N) prefix */
  92. uchar v6allnodesL[IPaddrlen] = {
  93. 0xff, 0x02, 0, 0,
  94. 0, 0, 0, 0,
  95. 0, 0, 0, 0,
  96. 0, 0, 0, 0x01
  97. };
  98. uchar v6allroutersL[IPaddrlen] = {
  99. 0xff, 0x02, 0, 0,
  100. 0, 0, 0, 0,
  101. 0, 0, 0, 0,
  102. 0, 0, 0, 0x02
  103. };
  104. uchar v6allnodesLmask[IPaddrlen] = {
  105. 0xff, 0xff, 0, 0,
  106. 0, 0, 0, 0,
  107. 0, 0, 0, 0,
  108. 0, 0, 0, 0
  109. };
  110. int v6aLpreflen = 2; /* all nodes (L) prefix */
  111. uchar v6solicitednode[IPaddrlen] = {
  112. 0xff, 0x02, 0, 0,
  113. 0, 0, 0, 0,
  114. 0, 0, 0, 0x01,
  115. 0xff, 0, 0, 0
  116. };
  117. uchar v6solicitednodemask[IPaddrlen] = {
  118. 0xff, 0xff, 0xff, 0xff,
  119. 0xff, 0xff, 0xff, 0xff,
  120. 0xff, 0xff, 0xff, 0xff,
  121. 0xff, 0x0, 0x0, 0x0
  122. };
  123. int v6snpreflen = 13;
  124. ushort
  125. ptclcsum(Block *bp, int offset, int len)
  126. {
  127. uchar *addr;
  128. ulong losum, hisum;
  129. ushort csum;
  130. int odd, blocklen, x;
  131. /* Correct to front of data area */
  132. while(bp != nil && offset && offset >= BLEN(bp)) {
  133. offset -= BLEN(bp);
  134. bp = bp->next;
  135. }
  136. if(bp == nil)
  137. return 0;
  138. addr = bp->rp + offset;
  139. blocklen = BLEN(bp) - offset;
  140. if(bp->next == nil) {
  141. if(blocklen < len)
  142. len = blocklen;
  143. return ~ptclbsum(addr, len) & 0xffff;
  144. }
  145. losum = 0;
  146. hisum = 0;
  147. odd = 0;
  148. while(len) {
  149. x = blocklen;
  150. if(len < x)
  151. x = len;
  152. csum = ptclbsum(addr, x);
  153. if(odd)
  154. hisum += csum;
  155. else
  156. losum += csum;
  157. odd = (odd+x) & 1;
  158. len -= x;
  159. bp = bp->next;
  160. if(bp == nil)
  161. break;
  162. blocklen = BLEN(bp);
  163. addr = bp->rp;
  164. }
  165. losum += hisum>>8;
  166. losum += (hisum&0xff)<<8;
  167. while((csum = losum>>16) != 0)
  168. losum = csum + (losum & 0xffff);
  169. return ~losum & 0xffff;
  170. }
  171. enum
  172. {
  173. Isprefix= 16,
  174. };
  175. #define CLASS(p) ((*(uchar*)(p))>>6)
  176. void
  177. ipv62smcast(uchar *smcast, uchar *a)
  178. {
  179. assert(IPaddrlen == 16);
  180. memmove(smcast, v6solicitednode, IPaddrlen);
  181. smcast[13] = a[13];
  182. smcast[14] = a[14];
  183. smcast[15] = a[15];
  184. }
  185. /*
  186. * parse a hex mac address
  187. */
  188. int
  189. parsemac(uchar *to, char *from, int len)
  190. {
  191. char nip[4];
  192. char *p;
  193. int i;
  194. p = from;
  195. memset(to, 0, len);
  196. for(i = 0; i < len; i++){
  197. if(p[0] == '\0' || p[1] == '\0')
  198. break;
  199. nip[0] = p[0];
  200. nip[1] = p[1];
  201. nip[2] = '\0';
  202. p += 2;
  203. to[i] = strtoul(nip, 0, 16);
  204. if(*p == ':')
  205. p++;
  206. }
  207. return i;
  208. }
  209. /*
  210. * hashing tcp, udp, ... connections
  211. */
  212. ulong
  213. iphash(uchar *sa, ushort sp, uchar *da, ushort dp)
  214. {
  215. return ((sa[IPaddrlen-1]<<24) ^ (sp << 16) ^ (da[IPaddrlen-1]<<8) ^ dp ) % Nhash;
  216. }
  217. void
  218. iphtadd(Ipht *ht, Conv *c)
  219. {
  220. ulong hv;
  221. Iphash *h;
  222. hv = iphash(c->raddr, c->rport, c->laddr, c->lport);
  223. h = smalloc(sizeof(*h));
  224. if(ipcmp(c->raddr, IPnoaddr) != 0)
  225. h->match = IPmatchexact;
  226. else {
  227. if(ipcmp(c->laddr, IPnoaddr) != 0){
  228. if(c->lport == 0)
  229. h->match = IPmatchaddr;
  230. else
  231. h->match = IPmatchpa;
  232. } else {
  233. if(c->lport == 0)
  234. h->match = IPmatchany;
  235. else
  236. h->match = IPmatchport;
  237. }
  238. }
  239. h->c = c;
  240. lock(ht);
  241. h->next = ht->tab[hv];
  242. ht->tab[hv] = h;
  243. unlock(ht);
  244. }
  245. void
  246. iphtrem(Ipht *ht, Conv *c)
  247. {
  248. ulong hv;
  249. Iphash **l, *h;
  250. hv = iphash(c->raddr, c->rport, c->laddr, c->lport);
  251. lock(ht);
  252. for(l = &ht->tab[hv]; (*l) != nil; l = &(*l)->next)
  253. if((*l)->c == c){
  254. h = *l;
  255. (*l) = h->next;
  256. free(h);
  257. break;
  258. }
  259. unlock(ht);
  260. }
  261. /* look for a matching conversation with the following precedence
  262. * connected && raddr,rport,laddr,lport
  263. * announced && laddr,lport
  264. * announced && *,lport
  265. * announced && laddr,*
  266. * announced && *,*
  267. */
  268. Conv*
  269. iphtlook(Ipht *ht, uchar *sa, ushort sp, uchar *da, ushort dp)
  270. {
  271. ulong hv;
  272. Iphash *h;
  273. Conv *c;
  274. /* exact 4 pair match (connection) */
  275. hv = iphash(sa, sp, da, dp);
  276. lock(ht);
  277. for(h = ht->tab[hv]; h != nil; h = h->next){
  278. if(h->match != IPmatchexact)
  279. continue;
  280. c = h->c;
  281. if(sp == c->rport && dp == c->lport
  282. && ipcmp(sa, c->raddr) == 0 && ipcmp(da, c->laddr) == 0){
  283. unlock(ht);
  284. return c;
  285. }
  286. }
  287. /* match local address and port */
  288. hv = iphash(IPnoaddr, 0, da, dp);
  289. for(h = ht->tab[hv]; h != nil; h = h->next){
  290. if(h->match != IPmatchpa)
  291. continue;
  292. c = h->c;
  293. if(dp == c->lport && ipcmp(da, c->laddr) == 0){
  294. unlock(ht);
  295. return c;
  296. }
  297. }
  298. /* match just port */
  299. hv = iphash(IPnoaddr, 0, IPnoaddr, dp);
  300. for(h = ht->tab[hv]; h != nil; h = h->next){
  301. if(h->match != IPmatchport)
  302. continue;
  303. c = h->c;
  304. if(dp == c->lport){
  305. unlock(ht);
  306. return c;
  307. }
  308. }
  309. /* match local address */
  310. hv = iphash(IPnoaddr, 0, da, 0);
  311. for(h = ht->tab[hv]; h != nil; h = h->next){
  312. if(h->match != IPmatchaddr)
  313. continue;
  314. c = h->c;
  315. if(ipcmp(da, c->laddr) == 0){
  316. unlock(ht);
  317. return c;
  318. }
  319. }
  320. /* look for something that matches anything */
  321. hv = iphash(IPnoaddr, 0, IPnoaddr, 0);
  322. for(h = ht->tab[hv]; h != nil; h = h->next){
  323. if(h->match != IPmatchany)
  324. continue;
  325. c = h->c;
  326. unlock(ht);
  327. return c;
  328. }
  329. unlock(ht);
  330. return nil;
  331. }