xref: /inferno-os/appl/lib/ip.b (revision 3293d1240801e46dd9cc27f6ba1133bc2b1d22e1)
1implement IP;
2
3#
4# Copyright © 2003,2004 Vita Nuova Holdings Limited.  All rights reserved.
5#
6
7include "sys.m";
8	sys: Sys;
9
10include "ip.m";
11
12init()
13{
14	sys = load Sys Sys->PATH;
15	v4prefix = array[] of {
16		byte 0, byte 0, byte 0, byte 0,
17		byte 0, byte 0, byte 0, byte 0,
18		byte 0, byte 0, byte 16rFF, byte 16rFF,
19	};
20
21	v4bcast = IPaddr(array[] of {
22		byte 0, byte 0, byte 0, byte 0,
23		byte 0, byte 0, byte 0, byte 0,
24		byte 0, byte 0, byte 16rFF, byte 16rFF,
25		byte 16rFF, byte 16rFF, byte 16rFF, byte 16rFF,
26	});
27
28	v4allsys = IPaddr(array[] of {
29		byte 0, byte 0, byte 0, byte 0,
30		byte 0, byte 0, byte 0, byte 0,
31		byte 0, byte 0, byte 16rFF, byte 16rFF,
32		byte 16rE0, byte 0, byte 0, byte 16r01,
33	});
34
35	v4allrouter = IPaddr(array[] of {
36		byte 0, byte 0, byte 0, byte 0,
37		byte 0, byte 0, byte 0, byte 0,
38		byte 0, byte 0, byte 16rFF, byte 16rFF,
39		byte 16rE0, byte 0, byte 0, byte 16r02,
40	});
41
42	v4noaddr = IPaddr(array[] of {
43		byte 0, byte 0, byte 0, byte 0,
44		byte 0, byte 0, byte 0, byte 0,
45		byte 0, byte 0, byte 16rFF, byte 16rFF,
46		byte 0, byte 0, byte 0, byte 0,
47	});
48
49	selfv6 = IPaddr(array[] of {
50		byte 0, byte 0, byte 0, byte 0,
51		byte 0, byte 0, byte 0, byte 0,
52		byte 0, byte 0, byte 0, byte 0,
53		byte 0, byte 0, byte 0, byte 1,
54	});
55
56	selfv4 = IPaddr(array[] of {
57		byte 0, byte 0, byte 0, byte 0,
58		byte 0, byte 0, byte 0, byte 0,
59		byte 0, byte 0, byte 16rFF, byte 16rFF,
60		byte 127, byte 0, byte 0, byte 1,
61	});
62
63	noaddr = IPaddr(array[] of {0 to IPaddrlen-1 => byte 0});
64	allbits = IPaddr(array[] of {0 to IPaddrlen-1 => byte 16rFF});
65}
66
67IPaddr.newv6(a: array of byte): IPaddr
68{
69	b := array[IPaddrlen] of byte;
70	b[0:] = a[0:IPaddrlen];
71	return IPaddr(b);
72}
73
74IPaddr.newv4(a: array of byte): IPaddr
75{
76	b := array[IPaddrlen] of byte;
77	b[0:] = v4prefix;
78	b[IPv4off:] = a[0:IPv4addrlen];
79	return IPaddr(b);
80}
81
82IPaddr.copy(ip: self IPaddr): IPaddr
83{
84	if(ip.a == nil)
85		return noaddr.copy();
86	a := array[IPaddrlen] of byte;
87	a[0:] = ip.a;
88	return IPaddr(a);
89}
90
91IPaddr.eq(ip: self IPaddr, v: IPaddr): int
92{
93	a := ip.a;
94	if(a == nil)
95		a = noaddr.a;
96	b := v.a;
97	if(b == nil)
98		b = noaddr.a;
99	for(i := 0; i < IPaddrlen; i++)
100		if(a[i] != b[i])
101			return 0;
102	return 1;
103}
104
105IPaddr.mask(a1: self IPaddr, a2: IPaddr): IPaddr
106{
107	c := array[IPaddrlen] of byte;
108	for(i := 0; i < IPaddrlen; i++)
109		c[i] = a1.a[i] & a2.a[i];
110	return IPaddr(c);
111}
112
113IPaddr.maskn(a1: self IPaddr, a2: IPaddr): IPaddr
114{
115	c := array[IPaddrlen] of byte;
116	for(i := 0; i < IPaddrlen; i++)
117		c[i] = a1.a[i] & ~a2.a[i];
118	return IPaddr(c);
119}
120
121IPaddr.isv4(ip: self IPaddr): int
122{
123	for(i := 0; i < IPv4off; i++)
124		if(ip.a[i] != v4prefix[i])
125			return 0;
126	return 1;
127}
128
129IPaddr.ismulticast(ip: self IPaddr): int
130{
131	if(ip.isv4()){
132		v := int ip.a[IPv4off];
133		return v >= 16rE0 && v < 16rF0 || ip.eq(v4bcast);	# rfc1112
134	}
135	return ip.a[0] == byte 16rFF;
136}
137
138IPaddr.isvalid(ip: self IPaddr): int
139{
140	return !ip.eq(noaddr) && !ip.eq(v4noaddr);
141}
142
143IPaddr.v4(ip: self IPaddr): array of byte
144{
145	if(!ip.isv4() && !ip.eq(noaddr))
146		return nil;
147	a := array[4] of byte;
148	for(i := 0; i < 4; i++)
149		a[i] = ip.a[IPv4off+i];
150	return a;
151}
152
153IPaddr.v6(ip: self IPaddr): array of byte
154{
155	a := array[IPaddrlen] of byte;
156	a[0:] = ip.a;
157	return a;
158}
159
160IPaddr.class(ip: self IPaddr): int
161{
162	if(!ip.isv4())
163		return 6;
164	return int ip.a[IPv4off]>>6;
165}
166
167IPaddr.classmask(ip: self IPaddr): IPaddr
168{
169	m := allbits.copy();
170	if(!ip.isv4())
171		return m;
172	if((n := ip.class()) == 0)
173		n = 1;
174	for(i := IPaddrlen-4+n; i < IPaddrlen; i++)
175		m.a[i] = byte 0;
176	return m;
177}
178
179#
180# rfc2373
181#
182
183IPaddr.parse(s: string): (int, IPaddr)
184{
185	a := noaddr.copy();
186	col := 0;
187	gap := 0;
188	for(i:=0; i<IPaddrlen && s != ""; i+=2){
189		c := 'x';
190		v := 0;
191		for(m := 0; m < len s && (c = s[m]) != '.' && c != ':'; m++){
192			d := 0;
193			if(c >= '0' && c <= '9')
194				d = c-'0';
195			else if(c >= 'a' && c <= 'f')
196				d = c-'a'+10;
197			else if(c >= 'A' && c <= 'F')
198				d = c-'A'+10;
199			else
200				return (-1, a);
201			v = (v<<4) | d;
202		}
203		if(c == '.'){
204			if(parseipv4(a.a[i:], s) < 0)
205				return (-1, noaddr.copy());
206			i += IPv4addrlen;
207			break;
208		}
209		if(v > 16rFFFF)
210			return (-1, a);
211		a.a[i] = byte (v>>8);
212		a.a[i+1] = byte v;
213		if(c == ':'){
214			col = 1;
215			if(++m < len s && s[m] == ':'){
216				if(gap > 0)
217					return (-1, a);
218				gap = i+2;
219				m++;
220			}
221		}
222		s = s[m:];
223	}
224	if(i < IPaddrlen){	# mind the gap
225		ns := i-gap;
226		for(j := 1; j <= ns; j++){
227			a.a[IPaddrlen-j] = a.a[i-j];
228			a.a[i-j] = byte 0;
229		}
230	}
231	if(!col)
232		a.a[0:] = v4prefix;
233	return (0, IPaddr(a));
234}
235
236IPaddr.parsemask(s: string): (int, IPaddr)
237{
238	return parsemask(s, 128);
239}
240
241IPaddr.parsecidr(s: string): (int, IPaddr, IPaddr)
242{
243	for(i := 0; i < len s && s[i] != '/'; i++)
244		;
245	(ok, a) := IPaddr.parse(s[0:i]);
246	if(i < len s){
247		(ok2, m) := IPaddr.parsemask(s[i:]);
248		if(ok < 0 || ok2 < 0)
249			return (-1, a, m);
250		return (0, a, m);
251	}
252	return (ok, a, allbits.copy());
253}
254
255parseipv4(b: array of byte, s: string): int
256{
257	a := array[4] of {* => 0};
258	o := 0;
259	for(i := 0; i < 4 && o < len s; i++){
260		for(m := o; m < len s && (c := s[m]) != '.'; m++)
261			if(!(c >= '0' && c <= '9'))
262				return -1;
263		if(m == o)
264			return -1;
265		a[i] = int big s[o:m];
266		b[i] = byte a[i];
267		if(m < len s && s[m] == '.')
268			m++;
269		o = m;
270	}
271	case i {
272	1 =>		# 32 bit
273		b[0] = byte (a[0] >> 24);
274		b[1] = byte (a[0] >> 16);
275		b[2] = byte (a[0] >> 8);
276		b[3] = byte a[0];
277	2 =>
278		if(a[0] < 256){	# 8/24
279			b[0] = byte a[0];
280			b[1] = byte (a[1]>>16);
281			b[2] = byte (a[1]>>8);
282		}else if(a[0] < 65536){	# 16/16
283			b[0] = byte (a[0]>>8);
284			b[1] = byte a[0];
285			b[2] = byte (a[1]>>16);
286		}else{	# 24/8
287			b[0] = byte (a[0]>>16);
288			b[1] = byte (a[0]>>8);
289			b[2] = byte a[0];
290		}
291		b[3] = byte a[1];
292	3 =>		# 8/8/16
293		b[0] = byte a[0];
294		b[1] = byte a[1];
295		b[2] = byte (a[2]>>16);
296		b[3] = byte a[2];
297	}
298	return 0;
299}
300
301parsemask(s: string, abits: int): (int, IPaddr)
302{
303	m := allbits.copy();
304	if(s == nil)
305		return (0, m);
306	if(s[0] != '/'){
307		(ok, a) := IPaddr.parse(s);
308		if(ok < 0)
309			return (0, m);
310		if(a.isv4())
311			a.a[0:] = m.a[0:IPv4off];
312		return (0, a);
313	}
314	if(len s == 1)
315		return (0, m);
316	nbit := int s[1:];
317	if(nbit < 0)
318		return (-1, m);
319	if(nbit > abits)
320		return (0, m);
321	nbit = abits-nbit;
322	i := IPaddrlen;
323	for(; nbit >= 8; nbit -= 8)
324		m.a[--i] = byte 0;
325	if(nbit > 0)
326		m.a[i-1] &= byte (~0<<nbit);
327	return (0, m);
328}
329
330IPaddr.text(a: self IPaddr): string
331{
332	b := a.a;
333	if(b == nil)
334		return "::";
335	if(a.isv4())
336		return sys->sprint("%d.%d.%d.%d", int b[IPv4off], int b[IPv4off+1], int b[IPv4off+2], int b[IPv4off+3]);
337	cs := -1;
338	nc := 0;
339	for(i:=0; i<IPaddrlen; i+=2)
340		if(int b[i] == 0 && int b[i+1] == 0){
341			for(j:=i+2; j<IPaddrlen; j+=2)
342				if(int b[j] != 0 || int b[j+1] != 0)
343					break;
344			if(j-i > nc){
345				nc = j-i;
346				cs = i;
347			}
348		}
349	if(nc <= 2)
350		cs = -1;
351	s := "";
352	for(i=0; i<IPaddrlen; ){
353		if(i == cs){
354			s += "::";
355			i += nc;
356		}else{
357			if(s != "" && s[len s-1]!=':')
358				s[len s] = ':';
359			v := (int a.a[i] << 8) | int a.a[i+1];
360			s += sys->sprint("%ux", v);
361			i += 2;
362		}
363	}
364	return s;
365}
366
367IPaddr.masktext(a: self IPaddr): string
368{
369	b := a.a;
370	if(b == nil)
371		return "/0";
372	for(i:=0; i<IPaddrlen; i++)
373		if(i == IPv4off)
374			return sys->sprint("%d.%d.%d.%d", int b[IPv4off], int b[IPv4off+1], int b[IPv4off+2], int b[IPv4off+3]);
375		else if(b[i] != byte 16rFF)
376			break;
377	for(j:=i+1; j<IPaddrlen; j++)
378		if(b[j] != byte 0)
379			return a.text();
380	nbit := 8*i;
381	if(i < IPaddrlen){
382		v := int b[i];
383		for(m := 16r80; m != 0; m >>= 1){
384			if((v & m) == 0)
385				break;
386			v &= ~m;
387			nbit++;
388		}
389		if(v != 0)
390			return a.text();
391	}
392	return sys->sprint("/%d", nbit);
393}
394
395addressesof(ifcs: list of ref Ipifc, all: int): list of IPaddr
396{
397	ra: list of IPaddr;
398	runi: list of IPaddr;
399	for(; ifcs != nil; ifcs = tl ifcs){
400		for(ifcas :=(hd ifcs).addrs; ifcs != nil; ifcs = tl ifcs){
401			a := (hd ifcas).ip;
402			if(all || !(a.eq(noaddr) || a.eq(v4noaddr))){	# ignore unspecified and loopback
403				if(a.ismulticast() || a.eq(selfv4) || a.eq(selfv6))
404					ra = a :: ra;
405				else
406					runi = a :: runi;
407			}
408		}
409	}
410	# unicast first, then others, both sets in order as found
411	# for ipv6, might want to give priority to unicast other than link- and site-local
412	al: list of IPaddr;
413	for(; ra != nil; ra = tl ra)
414		al = hd ra :: al;
415	for(; runi != nil; runi = tl runi)
416		al = hd runi :: al;
417	return al;
418}
419
420interfaceof(l: list of ref Ipifc, ip: IPaddr): (ref Ipifc, ref Ifcaddr)
421{
422	for(; l != nil; l = tl l){
423		ifc := hd l;
424		for(addrs := ifc.addrs; addrs != nil; addrs = tl addrs){
425			a := hd addrs;
426			if(ip.mask(a.mask).eq(a.net))
427				return (ifc, a);
428		}
429	}
430	return (nil, nil);
431}
432
433ownerof(l: list of ref Ipifc, ip: IPaddr): (ref Ipifc, ref Ifcaddr)
434{
435	for(; l != nil; l = tl l){
436		ifc := hd l;
437		for(addrs := ifc.addrs; addrs != nil; addrs = tl addrs){
438			a := hd addrs;
439			if(ip.eq(a.ip))
440				return (ifc, a);
441		}
442	}
443	return (nil, nil);
444}
445
446readipifc(net: string, index: int): (list of ref Ipifc, string)
447{
448	if(net == nil)
449		net = "/net";
450	if(index < 0){
451		ifcs: list of ref Ipifc;
452		dirfd := sys->open(net+"/ipifc", Sys->OREAD);
453		if(dirfd == nil)
454			return (nil, sys->sprint("%r"));
455		err: string;
456		for(;;){
457			(nd, dirs) := sys->dirread(dirfd);
458			if(nd <= 0){
459				if(nd < 0)
460					err = sys->sprint("%r");
461				break;
462			}
463			for(i:=0; i<nd; i++)
464				if((dn := dirs[i].name) != nil && dn[0]>='0' && dn[0]<='9'){
465					index = int dn;
466					ifc := readstatus(net+"/ipifc/"+dn+"/status", index);
467					if(ifc != nil)
468						ifcs = ifc :: ifcs;
469				}
470		}
471		l := ifcs;
472		for(ifcs = nil; l != nil; l = tl l)
473			ifcs = hd l :: ifcs;
474		return (ifcs, err);
475	}
476	ifc := readstatus(net+"/ipifc/"+string index+"/status", index);
477	if(ifc == nil)
478		return (nil, sys->sprint("%r"));
479	return (ifc :: nil, nil);
480}
481
482#
483# return data structure containing values read from status file:
484#
485# device /net/ether0 maxtu 1514 sendra 0 recvra 0 mflag 0 oflag 0 maxraint 600000 minraint 200000 linkmtu 0 reachtime 0 rxmitra 0 ttl 255 routerlt 1800000 pktin 47609 pktout 42322 errin 0 errout 0
486#	144.32.112.83 /119 144.32.112.0 4294967295   4294967295
487#		...
488#
489
490readstatus(file: string, index: int): ref Ipifc
491{
492	fd := sys->open(file, Sys->OREAD);
493	if(fd == nil)
494		return nil;
495	contents := slurp(fd);
496	fd = nil;
497	(nline, lines) := sys->tokenize(contents, "\n");
498	if(nline <= 0){
499		sys->werrstr("unexpected ipifc status file format");
500		return nil;
501	}
502	(nil, details) := sys->tokenize(hd lines, " \t\n");
503	lines = tl lines;
504	ifc := ref Ipifc;
505	ifc.index = index;
506	ifc.dev = valof(details, "device");
507	ifc.mtu = int valof(details, "maxtu");
508	ifc.pktin = big valof(details, "pktin");
509	ifc.pktout = big valof(details, "pktout");
510	ifc.errin = big valof(details, "errin");
511	ifc.errout = big valof(details, "errout");
512	ifc.sendra = int valof(details, "sendra");
513	ifc.recvra = int valof(details, "recvra");
514	ifc.rp.mflag = int valof(details, "mflag");
515	ifc.rp.oflag = int valof(details, "oflag");
516	ifc.rp.maxraint = int valof(details, "maxraint");
517	ifc.rp.minraint = int valof(details, "minraint");
518	ifc.rp.linkmtu = int valof(details, "linkmtu");
519	ifc.rp.reachtime = int valof(details, "reachtime");
520	ifc.rp.rxmitra = int valof(details, "rxmitra");
521	ifc.rp.ttl = int valof(details, "ttl");
522	ifc.rp.routerlt = int valof(details, "routerlt");
523	addrs: list of ref Ifcaddr;
524	for(; lines != nil; lines = tl lines){
525		(nf, fields) := sys->tokenize(hd lines, " \t\n");
526		if(nf >= 3){
527			addr := ref Ifcaddr;
528			(nil, addr.ip) = IPaddr.parse(hd fields); fields = tl fields;
529			(nil, addr.mask) = IPaddr.parsemask(hd fields); fields = tl fields;
530			(nil, addr.net) = IPaddr.parse(hd fields); fields = tl fields;
531			if(nf >= 5){
532				addr.preflt = big hd fields; fields = tl fields;
533				addr.validlt = big hd fields; fields = tl fields;
534			}else{
535				addr.preflt = big 0;
536				addr.validlt = big 0;
537			}
538			addrs = addr :: addrs;
539		}
540	}
541	for(; addrs != nil; addrs = tl addrs)
542		ifc.addrs = hd addrs :: ifc.addrs;
543	return ifc;
544}
545
546slurp(fd: ref Sys->FD): string
547{
548	buf := array[2048] of byte;
549	s := "";
550	while((n := sys->read(fd, buf, len buf)) > 0)
551		s += string buf[0:n];
552	return s;
553}
554
555valof(l: list of string, attr: string): string
556{
557	while(l != nil){
558		label := hd l;
559		l = tl l;
560		if(label == attr){
561			if(l == nil)
562				return nil;
563			return hd l;
564		}
565		if(l != nil)
566			l = tl l;
567	}
568	return nil;
569}
570
571Udphdr.new(): ref Udphdr
572{
573	return ref Udphdr(noaddr, noaddr, noaddr, 0, 0);
574}
575
576Udphdr.unpack(a: array of byte, n: int): ref Udphdr
577{
578	case n {
579	Udp4hdrlen =>
580		u := ref Udphdr;
581		u.raddr = IPaddr.newv4(a[0:]);
582		u.laddr = IPaddr.newv4(a[IPv4addrlen:]);
583		u.rport = get2(a, 2*IPv4addrlen);
584		u.lport = get2(a, 2*IPv4addrlen+2);
585		u.ifcaddr = u.laddr.copy();
586		return u;
587	OUdphdrlen =>
588		u := ref Udphdr;
589		u.raddr = IPaddr.newv6(a[0:]);
590		u.laddr = IPaddr.newv6(a[IPaddrlen:]);
591		u.rport = get2(a, 2*IPaddrlen);
592		u.lport = get2(a, 2*IPaddrlen+2);
593		u.ifcaddr = u.laddr.copy();
594		return u;
595	Udphdrlen =>
596		u := ref Udphdr;
597		u.raddr = IPaddr.newv6(a[0:]);
598		u.laddr = IPaddr.newv6(a[IPaddrlen:]);
599		u.ifcaddr = IPaddr.newv6(a[2*IPaddrlen:]);
600		u.rport = get2(a, 3*IPaddrlen);
601		u.lport = get2(a, 3*IPaddrlen+2);
602		return u;
603	* =>
604		raise "Udphdr.unpack: bad length";
605	}
606}
607
608Udphdr.pack(u: self ref Udphdr, a: array of byte, n: int)
609{
610	case n {
611	Udp4hdrlen =>
612		a[0:] = u.raddr.v4();
613		a[IPv4addrlen:] = u.laddr.v4();
614		put2(a, 2*IPv4addrlen, u.rport);
615		put2(a, 2*IPv4addrlen+2, u.lport);
616	OUdphdrlen =>
617		a[0:] = u.raddr.v6();
618		a[IPaddrlen:] = u.laddr.v6();
619		put2(a, 2*IPaddrlen, u.rport);
620		put2(a, 2*IPaddrlen+2, u.lport);
621	Udphdrlen =>
622		a[0:] = u.raddr.v6();
623		a[IPaddrlen:] = u.laddr.v6();
624		a[2*IPaddrlen:] = u.ifcaddr.v6();
625		put2(a, 3*IPaddrlen, u.rport);
626		put2(a, 3*IPaddrlen+2, u.lport);
627	* =>
628		raise "Udphdr.pack: bad length";
629	}
630}
631
632get2(a: array of byte, o: int): int
633{
634	return (int a[o] << 8) | int a[o+1];
635}
636
637put2(a: array of byte, o: int, val: int): int
638{
639	a[o] = byte (val>>8);
640	a[o+1] = byte val;
641	return o+2;
642}
643
644get4(a: array of byte, o: int): int
645{
646	return (((((int a[o] << 8)| int a[o+1]) << 8) | int a[o+2]) << 8) | int a[o+3];
647}
648
649put4(a: array of byte, o: int, val: int): int
650{
651	a[o] = byte (val>>24);
652	a[o+1] = byte (val>>16);
653	a[o+2] = byte (val>>8);
654	a[o+3] = byte val;
655	return o+4;
656}
657