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