123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487 |
- (* Aos Runtime: IP, Copyright 2005, Emil J. Zeller *)
- (* Aos, Copyright 2001, Pieter Muller, ETH Zurich *)
- MODULE IP; (** AUTHOR "pjm, mvt"; PURPOSE "IP and ARP protocols"; *)
- IMPORT SYSTEM, WSock32, Network, Strings, Kernel, KernelLog;
- CONST
- (** Error codes *)
- Ok* = 0;
-
- (** TCP connection states *)
- NumStates* = 12; Closed* = 0; Listen* = 1; SynSent* = 2;
- SynReceived* = 3; Established* = 4; CloseWait* = 5; FinWait1* = 6;
- Closing* = 7; LastAck* = 8; FinWait2* = 9; TimeWait* = 10;
- Unused* = 11; (* no real state, only used in this implementation *)
-
- Trace=TRUE;
- (** IP address constants *)
- NilAdrIPv4 = 0;
-
- NilPort* = 0;
- (* Comparators for Adr.usedProtocols *)
- IPv4* = 4;
- IPv6* = 6;
- NilAdrIdent = -1; (* usedProtocol of NilAdrs *)
- TYPE
- Adr* = RECORD
- ipv4Adr*: LONGINT;
- ipv6Adr*: ARRAY 16 OF CHAR;
- usedProtocol*: LONGINT;
- data*: LONGINT;
- END; (** An IP Address. usedProtocol = 0: No protocol yet used
- usedProtocol = IPv4: IPv4 address stored in field ipv4Adr
- usedProtocol = IPv6: IPv6 address stored in field ipv6Adr
- data can be used to store additional informations. I.e. in IPv6 the
- prefix length is stored in the data field *)
- Name* = ARRAY 128 OF CHAR; (** Name type for interface name *)
- (** IP interface. See note at the end of the module. *)
- Interface* = OBJECT
- VAR
- (** IP addresses of this interface *)
- localAdr-: Adr;
- next*:Interface;
- END Interface;
-
- VAR
- pool*: Kernel.FinalizedCollection; (* pool of all IP.Socket *)
-
- (* Interfaces *)
- default-: Interface;
- interfaces*: Interface; (* list of all installed interfaces *)
- (* IP *)
- NilAdr*: Adr; (* To check if an IP address is NIL use IsNilAdr instead *)
- (** Is address not yet specified *)
- PROCEDURE IsNilAdr* (adr: Adr): BOOLEAN;
- VAR
- isNil: BOOLEAN;
- i: LONGINT;
- BEGIN
- CASE adr.usedProtocol OF
- IPv4:
- RETURN (adr.ipv4Adr = NilAdrIPv4)
- |IPv6:
- isNil := TRUE;
- i := 0;
- WHILE ((i<16) & isNil) DO
- IF adr.ipv6Adr[i] # 0X THEN
- isNil := FALSE;
- END;
- INC(i);
- END;
- RETURN isNil;
- |NilAdrIdent:
- RETURN TRUE;
- ELSE
- RETURN TRUE;
- END;
- END IsNilAdr;
- (* Checks if two addresses are equal *)
- PROCEDURE AdrsEqual* (adr1, adr2: Adr): BOOLEAN;
- VAR
- equal: BOOLEAN;
- i: LONGINT;
- BEGIN
- IF adr1.usedProtocol # adr2.usedProtocol THEN
- RETURN FALSE;
- END;
- CASE adr1.usedProtocol OF
- IPv4:
- IF adr1.ipv4Adr = adr2.ipv4Adr THEN
- RETURN TRUE;
- END;
- |IPv6:
- equal := TRUE;
- i := 0;
- WHILE ((i < 16) & equal) DO
- IF adr1.ipv6Adr[i] # adr2.ipv6Adr[i] THEN
- equal := FALSE;
- END;
- INC(i);
- END;
- IF adr1.data # adr2.data THEN
- equal := FALSE;
- END;
- RETURN equal;
- |NilAdrIdent:
- (* both addresses NIL therefore equal *)
- IF adr2.usedProtocol = NilAdrIdent THEN
- RETURN TRUE;
- ELSE
- RETURN FALSE;
- END;
- ELSE
- RETURN FALSE;
- END;
- RETURN FALSE;
- END AdrsEqual;
- (** Convert a dotted-decimal string to an ip address. Return NilAdr on failure. *)
- PROCEDURE StrToAdr*(CONST s: ARRAY OF CHAR): Adr;
- VAR
- i, j, x: LONGINT;
- adr: ARRAY 4 OF CHAR;
- ok: BOOLEAN;
- ip: Adr;
- BEGIN
- i := 0; j := 0; x := -1; ok := FALSE;
- LOOP
- IF (s[i] = ".") OR (s[i] = 0X) THEN
- IF (x < 0) OR (x > 255) OR (j = 4) THEN EXIT END;
- adr[j] := CHR(x);
- IF s[i] = 0X THEN ok := (j = 3); EXIT END;
- x := -1; INC(i); INC(j)
- ELSIF (s[i] >= "0") & (s[i] <= "9") THEN
- IF x = -1 THEN x := 0 END;
- x := x*10 + (ORD(s[i])-ORD("0"));
- INC(i)
- ELSE
- EXIT
- END
- END;
- IF ok THEN
- ip.ipv4Adr := SYSTEM.VAL(LONGINT,adr);
- ip.usedProtocol := IPv4;
- RETURN ip;
- ELSE
- RETURN NilAdr;
- END
- END StrToAdr;
- (** Convert an IP address to a dotted-decimal string. *)
- PROCEDURE AdrToStr*(adr: Adr; VAR string: ARRAY OF CHAR);
- VAR
- i, j, x: LONGINT;
- a: ARRAY 4 OF CHAR;
- val : LONGINT;
- hexToStr: ARRAY 5 OF CHAR;
- prefixLenStr: ARRAY 64 OF CHAR;
- maxZeroRow: LONGINT;
- currentZeroRow: LONGINT;
- maxZeroStart: LONGINT;
- currentZeroStart: LONGINT;
- lastZero: BOOLEAN;
- lastDPoint: BOOLEAN;
- countEnded: BOOLEAN;
- BEGIN
- CASE adr.usedProtocol OF
- IPv4:
- ASSERT(LEN(string) >= 16); (* enough space for largest result *)
- Network.Put4(a, 0, adr.ipv4Adr);
- i := 0;
- FOR j := 0 TO 3 DO
- x := ORD(a[j]);
- IF x >= 100 THEN string[i] := CHR(ORD("0")+x DIV 100); INC(i) END;
- IF x >= 10 THEN string[i] := CHR(ORD("0")+x DIV 10 MOD 10); INC(i) END;
- string[i] := CHR(ORD("0")+x MOD 10); INC(i);
- IF j = 3 THEN string[i] := 0X ELSE string[i] := "." END;
- INC(i)
- END
- |IPv6:
- FOR i := 0 TO (LEN(adr.ipv6Adr) -1) BY 2 DO
- (* simple version *)
- val := ORD(adr.ipv6Adr[i]) * 256;
- val := val + ORD(adr.ipv6Adr[i+1]);
- Strings.IntToHexStr (val, 3, hexToStr);
- (* Delete leading zeros *)
- WHILE (hexToStr[0] = "0") & (hexToStr[1] # 0X) DO
- Strings.Delete(hexToStr, 0, 1);
- END;
- Strings.Append (string, hexToStr);
- IF i # (LEN(adr.ipv6Adr) - 2) THEN
- Strings.Append (string, ":");
- END;
- END;
- (* replace longest row of zeros with :: *)
- maxZeroRow := 0;
- currentZeroRow := 0;
- maxZeroStart := 0;
- currentZeroStart := 0;
- i := 0;
- lastZero := FALSE;
- lastDPoint := TRUE;
- countEnded :=TRUE;
- WHILE string[i] # 0X DO
- IF string[i] = "0" THEN
- IF lastDPoint THEN
- INC(currentZeroRow);
- lastZero := TRUE;
- lastDPoint := FALSE;
- IF countEnded THEN
- currentZeroStart := i;
- countEnded := FALSE;
- END;
- END;
- ELSIF string[i] = ":" THEN
- lastDPoint := TRUE;
- IF lastZero THEN
- lastZero := FALSE;
- END;
- ELSE
- IF lastDPoint THEN
- lastDPoint := FALSE;
- countEnded := TRUE;
- IF currentZeroRow > maxZeroRow THEN
- maxZeroRow := currentZeroRow;
- maxZeroStart := currentZeroStart;
- END;
- END;
- END;
- INC(i);
- END;
- IF ~countEnded THEN
- IF currentZeroRow > maxZeroRow THEN
- maxZeroRow := currentZeroRow;
- maxZeroStart := currentZeroStart;
- END;
- END;
- IF maxZeroRow # 0 THEN
- (* write a :: *)
- IF maxZeroStart = 0 THEN
- string[0] := ":";
- i := 1;
- WHILE ((string[i] # 0X) & ~((string[i] # "0") & (string[i] # ":"))) DO INC(i); END;
- IF string[i] = 0X THEN
- string := "::";
- ELSE
- Strings.Delete(string, 1, i-2);
- END;
- ELSE
- i := maxZeroStart;
- WHILE ((string[i] = "0") OR (string[i] = ":")) DO INC(i); END;
- IF string[i] = 0X THEN
- string[maxZeroStart] := ":";
- string[maxZeroStart+1] := 0X;
- ELSE
- Strings.Delete(string, maxZeroStart, i - maxZeroStart - 1);
- END;
- END;
- END;
- IF adr.data # 0 THEN
- (* write prefix *)
- Strings.IntToStr(adr.data, prefixLenStr);
- Strings.Append (string, "/");
- Strings.Append (string, prefixLenStr);
- END;
- ELSE
- IF IsNilAdr (adr) THEN
- string := "";
- END;
- END;
- END AdrToStr;
- (** Convert a IP address from an array [ofs..ofs+x] to an
- Adr-type variable.
- Example for IPv4:
- If the LSB (least significant byte) is stored the the beginning [ofs],
- LSBfirst must be set to TRUE.
- (address "a.b.c.d" is stored as [d,c,b,a])
- If the LSB is stored at the end [ofs+3], LSBfirst must be set to FALSE.
- (address "a.b.c.d" is stored as [a,b,c,d])
- *)
- PROCEDURE ArrayToAdr*(CONST array: ARRAY OF CHAR; ofs, protocol: LONGINT; LSBfirst: BOOLEAN): Adr;
- VAR
- adr: Adr;
- i, swapTemp: LONGINT;
- BEGIN
- ASSERT((protocol = 4) OR (protocol = 6));
- IF protocol = IPv4 THEN (* index check *)
- IF ~(ofs + 4 <= LEN(array)) THEN
- RETURN NilAdr;
- END;
- SYSTEM.MOVE(ADDRESSOF(array[ofs]), ADDRESSOF(adr.ipv4Adr), 4);
- IF LSBfirst THEN
- SwapEndian(adr.ipv4Adr);
- END;
- adr.usedProtocol := IPv4;
- ELSIF protocol = IPv6 THEN
- IF ~(ofs + 16 <= LEN(array)) THEN
- RETURN NilAdr;
- END;
- SYSTEM.MOVE(ADDRESSOF(array[ofs]), ADDRESSOF(adr.ipv6Adr), 16);
- IF LSBfirst THEN
- FOR i := 0 TO 3 DO
- SYSTEM.MOVE(ADDRESSOF(adr.ipv6Adr[i*4]), ADDRESSOF(swapTemp), 4);
- SwapEndian(swapTemp);
- SYSTEM.MOVE(ADDRESSOF(swapTemp), ADDRESSOF(adr.ipv6Adr[i*4]), 4);
- END;
- END;
- adr.usedProtocol := IPv6;
- ELSE
- RETURN NilAdr;
- END;
- RETURN adr;
- END ArrayToAdr;
- (** Convert an Adr-type variable into an array [ofs..ofs+x]
- Example in IPv4:
- If the LSB (least significant byte) should be stored the the
- beginning [ofs], LSBfirst must be set to TRUE.
- (address "a.b.c.d" is stored as [d,c,b,a])
- If the LSB should be stored at the end [ofs+3], LSBfirst must be set to FALSE.
- (address "a.b.c.d" is stored as [a,b,c,d])
- *)
- PROCEDURE AdrToArray*(adr: Adr; CONST array: ARRAY OF CHAR; ofs: LONGINT; LSBfirst: BOOLEAN);
- VAR
- tempAdr: Adr;
- i, swapTemp: LONGINT;
- BEGIN
- tempAdr := adr;
- CASE adr.usedProtocol OF
- IPv4:
- IF ~(ofs+4 <= LEN(array)) THEN
- tempAdr := NilAdr;
- END;
- IF LSBfirst THEN
- SwapEndian(tempAdr.ipv4Adr);
- END;
- SYSTEM.MOVE(ADDRESSOF(tempAdr.ipv4Adr), ADDRESSOF(array[ofs]), 4);
- | IPv6:
- IF ~(ofs + 16 <= LEN(array)) THEN
- tempAdr := NilAdr;
- END;
- IF LSBfirst THEN
- FOR i := 0 TO 3 DO
- SYSTEM.MOVE(ADDRESSOF(tempAdr.ipv6Adr[i*4]), ADDRESSOF(swapTemp), 4);
- SwapEndian(swapTemp);
- SYSTEM.MOVE(ADDRESSOF(swapTemp), ADDRESSOF(tempAdr.ipv6Adr[i*4]), 4);
- END;
- END;
- SYSTEM.MOVE(ADDRESSOF(adr.ipv6Adr), ADDRESSOF(array[ofs]), 16);
- ELSE
- END;
- END AdrToArray;
- (** Return the interface on which packets with "dst" address should be sent. Return NIL if no interface matches. *)
- PROCEDURE InterfaceByDstIP*(dst: Adr): Interface;(*! NYI*)
- BEGIN
- RETURN default
- END InterfaceByDstIP;
- (* Find MULTIPLE IP address of the specified host. *)
- PROCEDURE InitInterfaces( hostname: ARRAY OF CHAR; VAR res: WORD );
- VAR hostent: WSock32.PHostent; str: ARRAY 64 OF CHAR;
- adr, adr2: Adr;
- int0, int:Interface; i:LONGINT;
- addr: ADDRESS;
- BEGIN
- hostent := WSock32.gethostbyname(hostname);
- IF hostent = NIL THEN
- WSock32.DispError()
- ELSE
- WHILE hostent.hLength>0 DO
- adr.usedProtocol := IPv4;
- (*adr := hostent.hName;
- adr.ipv4Adr := hostent.hName;*)
- SYSTEM.GET(hostent.hAddrList+i*SIZEOF(ADDRESS), addr (*adr.ipv4Adr*));
- IF addr # NIL (*adr.ipv4Adr # 0*) THEN
- SYSTEM.GET(addr (*adr.ipv4Adr*), adr.ipv4Adr);
- NEW(int); int.localAdr:=adr;
- IF int0=NIL THEN
- int0:=int; interfaces:=int0; default:=int0;
- ELSE
- int0.next:=int; int0:=int;
- END;
- INC(i);
- KernelLog.String("added IP interface "); AdrToStr(adr, str); KernelLog.String(str); KernelLog.Ln;
- END;
- DEC(hostent.hLength);
- END;
- END;
- IF adr.ipv4Adr # 0 THEN res := Ok ELSE res := -1 END;
- END InitInterfaces;
- PROCEDURE Init;
- VAR name: ARRAY 256 OF CHAR; res: WORD;
- BEGIN
- KernelLog.String("IP.Init: Hostname ");
- res := WSock32.gethostname(name, 256);
- IF res = 0 THEN
- KernelLog.String(name);KernelLog.Ln;
- ELSE
- KernelLog.String("failed "); KernelLog.Int(res, 0);KernelLog.Ln;
- RETURN
- END;
-
- NilAdr.usedProtocol := IPv4;
-
- InitInterfaces(name, res);
- END Init;
- (* Swap internal representation of an IP address from big to little endian or vice versa. *)
- PROCEDURE -SwapEndian(VAR adr: LONGINT);
- CODE
- #IF I386 THEN
- POP EAX
- MOV ECX, [EAX]
- XCHG CL, CH
- ROL ECX, 16
- XCHG CL, CH
- MOV [EAX], ECX
- #ELSIF AMD64 THEN
- POP RAX
- MOV ECX, [RAX]
- XCHG CL, CH
- ROL ECX, 16
- XCHG CL, CH
- MOV [RAX], ECX
- #ELSE
- unimplemented
- #END
- END SwapEndian;
- BEGIN
- default := NIL;
- Init;
- END IP.
- System.FreeDownTo IP ~
|