123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647 |
- (* Aos, Copyright 2001, Pieter Muller, ETH Zurich *)
- MODULE IP; (** AUTHOR "pjm, mvt, eb, G.F."; PURPOSE "IP (v4 and v6)"; *)
- IMPORT S := SYSTEM, KernelLog, Strings, Network;
- CONST
- (** Error codes *)
- Ok* = 0;
- (** IP address constants *)
- NilAdrIPv4 = 0;
- (* Comparators for Adr.usedProtocols *)
- IPv4* = 4;
- IPv6* = 6;
- NilAdrIdent = -1; (* usedProtocol of NilAdrs *)
- MaxNofDNS = 4;
- 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 *)
- Packet* = POINTER TO ARRAY OF CHAR;
- Name* = ARRAY 128 OF CHAR; (** Name type for interface name *)
- ARPHandler* = PROCEDURE {DELEGATE} ( ip: Adr; complete: BOOLEAN;
- link: Network.LinkAdr;
- size, sendTime, updateTime, updateDate, hash: LONGINT);
- Interface* = OBJECT
- (*! unused in UnixAos, included only for interface compatibility
- mostly a dummy, only 'localAdr' contains valid data in UnixAos !! *)
- VAR
- (** IP addresses of this interface. *)
- localAdr-, maskAdr-, gatewayAdr-, subnetAdr-, broadAdr-: Adr;
- (** name of the interface *)
- name-: Name;
- (** Device that the interface belongs to *)
- dev-: Network.LinkDevice;
- (** DNS server list - can be used by DNS, not used in IP itself *)
- DNS-: ARRAY MaxNofDNS OF Adr; (* DNS server list *)
- DNScount-: LONGINT; (* number of DNS servers in list *)
- (* interface *)
- next*: Interface; (* next pointer for interface list *)
- closed-: BOOLEAN; (* is interface already closed? *)
- protocol-: LONGINT;
- (* Interface for IPv4 or IPv6?. Only used by IP otherwise use dynamic type checking! *)
- PROCEDURE & Init*( addr: Adr );
- BEGIN
- localAdr := addr;
- name := "dummy";
- END Init;
- END Interface;
- InterfaceHandler* = PROCEDURE {DELEGATE} (int: Interface);
- VAR
- (* IP *)
- NilAdr*: Adr; (* To check if an IP address is NIL use IsNilAdr instead *)
- preferredProtocol*: LONGINT; (* Preferred IP protocol *)
- (** 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*( ipString: ARRAY OF CHAR ): Adr;
- VAR retAdr: Adr; i, j, x: LONGINT;
- adr: ARRAY 4 OF CHAR;
- ok: BOOLEAN;
- charCount: LONGINT; (* ipv6: number of character between two : *)
- ipv6AdrPart: ARRAY 6 OF CHAR; (* two bytes of an IPv6 address *)
- ipv6AdrRight: ARRAY 16 OF CHAR; (* right part of an IPv6 address; after :: *)
- hexToChar: ARRAY 3 OF CHAR;
- leftParts: LONGINT; (* number of bytes before :: *)
- rightParts: LONGINT; (* number of bytes after :: *)
- val: LONGINT; res: WORD;
- state: LONGINT; (* state of the FSM look at the eof for more info *)
- dPointOcc: BOOLEAN; (* double point occured *)
- prefixVal: LONGINT;
- (* compute a subpart (two bytes) of a IPv6 address; subpart:=between two : *)
- PROCEDURE ComputeIPv6Part( ): BOOLEAN;
- BEGIN
- CASE charCount OF
- | 0: RETURN TRUE;
- | 1, 2: IF dPointOcc THEN ipv6AdrRight[rightParts] := 0X; INC( rightParts );
- ELSE retAdr.ipv6Adr[leftParts] := 0X; INC( leftParts );
- END;
- Strings.HexStrToInt( ipv6AdrPart, val, res );
- IF res = Strings.Ok THEN
- IF dPointOcc THEN ipv6AdrRight[rightParts] := CHR( val ); INC( rightParts );
- ELSE retAdr.ipv6Adr[leftParts] := CHR( val ); INC( leftParts );
- END;
- ELSE RETURN FALSE
- END;
- | 3: hexToChar[0] := ipv6AdrPart[0]; hexToChar[1] := 0X;
- Strings.HexStrToInt( hexToChar, val, res );
- IF res = Strings.Ok THEN
- IF dPointOcc THEN ipv6AdrRight[rightParts] := CHR( val ); INC( rightParts );
- ELSE retAdr.ipv6Adr[leftParts] := CHR( val ); INC( leftParts );
- END;
- ELSE RETURN FALSE
- END;
- ipv6AdrPart[0] := "0"; Strings.HexStrToInt( ipv6AdrPart, val, res );
- IF res = Strings.Ok THEN
- IF dPointOcc THEN ipv6AdrRight[rightParts] := CHR( val ); INC( rightParts );
- ELSE retAdr.ipv6Adr[leftParts] := CHR( val ); INC( leftParts );
- END;
- ELSE RETURN FALSE
- END;
- | 4: hexToChar[0] := ipv6AdrPart[0]; hexToChar[1] := ipv6AdrPart[1]; hexToChar[2] := 0X;
- Strings.HexStrToInt( hexToChar, val, res );
- IF res = Strings.Ok THEN
- IF dPointOcc THEN ipv6AdrRight[rightParts] := CHR( val ); INC( rightParts );
- ELSE retAdr.ipv6Adr[leftParts] := CHR( val ); INC( leftParts );
- END;
- ELSE RETURN FALSE
- END;
- ipv6AdrPart[0] := "0"; ipv6AdrPart[1] := "0"; Strings.HexStrToInt( ipv6AdrPart, val, res );
- IF res = Strings.Ok THEN
- IF dPointOcc THEN ipv6AdrRight[rightParts] := CHR( val ); INC( rightParts );
- ELSE retAdr.ipv6Adr[leftParts] := CHR( val ); INC( leftParts );
- END;
- ELSE RETURN FALSE
- END;
- ELSE RETURN FALSE;
- END;
- charCount := 0; RETURN TRUE;
- END ComputeIPv6Part;
- BEGIN
- retAdr := NilAdr;
- IF IsValidIPv4Str( ipString ) THEN
- (* Return an ipv4 address *)
- i := 0; j := 0; x := -1; ok := FALSE;
- LOOP
- IF (ipString[i] = ".") OR (ipString[i] = 0X) THEN
- IF (x < 0) OR (x > 255) OR (j = 4) THEN EXIT END;
- adr[j] := CHR( x );
- IF ipString[i] = 0X THEN ok := (j = 3); EXIT END;
- x := -1; INC( i ); INC( j )
- ELSIF (ipString[i] >= "0") & (ipString[i] <= "9") THEN
- IF x = -1 THEN x := 0 END;
- x := x*10 + (ORD( ipString[i] ) - ORD( "0" )); INC( i )
- ELSE EXIT
- END
- END;
- IF ok THEN retAdr.ipv4Adr := S.VAL( LONGINT, adr ); retAdr.usedProtocol := IPv4; RETURN retAdr;
- ELSE RETURN NilAdr;
- END
- ELSIF IsValidIPv6Str( ipString ) THEN
- i := 0; state := 1; charCount := 0; dPointOcc := FALSE;
- retAdr.usedProtocol := 6; retAdr.ipv4Adr := NilAdrIPv4;
- i := 0; j := 0; charCount := 0; leftParts := 0; rightParts := 0; prefixVal := 0;
- Strings.UpperCase( ipString );
- WHILE (i < (LEN( ipString ) - 1)) & (ipString[i] # 0X) DO
- CASE state OF (* Using the same FSM as IsValidIPv6Str *)
- | -1: (* Error state Should never happen, is checked by IsValidIPv6Str() *)
- RETURN NilAdr;
- | 1: (* reading two blocks of two bytes of 0-9\A-F *)
- IF ipString[i] = ":" THEN
- ipv6AdrPart[charCount] := 0X;
- IF ~ComputeIPv6Part() THEN RETURN NilAdr END;
- state := 2;
- ELSIF ipString[i] = "/" THEN
- ipv6AdrPart[charCount] := 0X;
- IF ~ComputeIPv6Part() THEN RETURN NilAdr END;
- state := 3;
- ELSE (* 0-9, A-F *)
- ipv6AdrPart[charCount] := ipString[i]; INC( charCount );
- END;
- | 2: (* a : occured *)
- IF ipString[i] = ":" THEN dPointOcc := TRUE; state := 4
- ELSE (* 0-9, A-F *)
- state := 1; charCount := 0; ipv6AdrPart[charCount] := ipString[i]; INC( charCount );
- END;
- | 3: (* prefix will follow *)
- prefixVal := (prefixVal*10) + (ORD( ipString[i] ) - ORD( "0" ));
- | 4: (* A :: occured *)
- IF ipString[i] = "/" THEN state := 3
- ELSE
- IF ~ComputeIPv6Part() THEN RETURN NilAdr END;
- (* 0-9, A-F *)
- state := 1; charCount := 0; ipv6AdrPart[charCount] := ipString[i]; INC( charCount )
- END;
- ELSE
- END;
- INC( i );
- END;
- ipv6AdrPart[charCount] := 0X;
- IF charCount # 0 THEN
- IF ~ComputeIPv6Part() THEN RETURN NilAdr END;
- END;
- IF dPointOcc THEN
- (* fill 0X for :: *)
- FOR i := leftParts TO ((LEN( retAdr.ipv6Adr ) - 1) - rightParts) DO retAdr.ipv6Adr[i] := 0X END;
- (* fill part behind :: *)
- FOR i := 0 TO (rightParts - 1) DO
- retAdr.ipv6Adr[(LEN( retAdr.ipv6Adr ) - rightParts) + i] := ipv6AdrRight[i]
- END;
- END;
- IF prefixVal > 64 THEN RETURN NilAdr END;
- retAdr.data := prefixVal; RETURN retAdr;
- END;
- RETURN NilAdr;
- 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:
- 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 COPY( "::", 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[0] := 0X 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 arr: 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( arr )) THEN RETURN NilAdr END;
- S.MOVE( ADDRESSOF( arr[ofs] ), ADDRESSOF( adr.ipv4Adr ), 4 );
- IF LSBfirst THEN SwapEndian( adr.ipv4Adr ) END;
- adr.usedProtocol := IPv4;
- ELSIF protocol = IPv6 THEN
- IF ~(ofs + 16 <= LEN( arr )) THEN RETURN NilAdr END;
- S.MOVE( ADDRESSOF( arr[ofs] ), ADDRESSOF( adr.ipv6Adr ), 16 );
- IF LSBfirst THEN
- FOR i := 0 TO 3 DO
- S.MOVE( ADDRESSOF( adr.ipv6Adr[i*4] ), ADDRESSOF( swapTemp ), 4 );
- SwapEndian( swapTemp );
- S.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; VAR arr: 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( arr )) THEN tempAdr := NilAdr END;
- IF LSBfirst THEN SwapEndian( tempAdr.ipv4Adr ) END;
- S.MOVE( ADDRESSOF( tempAdr.ipv4Adr ), ADDRESSOF( arr[ofs] ), 4 );
- | IPv6:
- IF ~(ofs + 16 <= LEN( arr )) THEN tempAdr := NilAdr END;
- IF LSBfirst THEN
- FOR i := 0 TO 3 DO
- S.MOVE( ADDRESSOF( tempAdr.ipv6Adr[i*4] ), ADDRESSOF( swapTemp ), 4 );
- SwapEndian( swapTemp );
- S.MOVE( ADDRESSOF( swapTemp ), ADDRESSOF( tempAdr.ipv6Adr[i*4] ), 4 );
- END;
- END;
- S.MOVE( ADDRESSOF( adr.ipv6Adr ), ADDRESSOF( arr[ofs] ), 16 );
- ELSE
- END;
- END AdrToArray;
- (** Aos command: Output statistics and configuration of all installed interfaces. *)
- PROCEDURE IPConfig*( par: ANY ): ANY;
- BEGIN
- KernelLog.String( "Interfaces:" ); KernelLog.Ln; RETURN NIL;
- END IPConfig;
- (* Return TRUE if adr matches the prefix *)
- PROCEDURE MatchPrefix*( adr: Adr; prefix: Adr ): BOOLEAN;
- VAR
- bytesToCheck: LONGINT; bitsToCheck: LONGINT; i: LONGINT; matches: BOOLEAN; diffSet: SET;
- BEGIN
- matches := TRUE;
- bytesToCheck := prefix.data DIV 8; bitsToCheck := prefix.data MOD 8;
- FOR i := 0 TO bytesToCheck - 1 DO
- IF adr.ipv6Adr[i] # prefix.ipv6Adr[i] THEN matches := FALSE END;
- END;
- IF bitsToCheck # 0 THEN
- diffSet := {};
- FOR i := 0 TO 8 - bitsToCheck - 1 DO diffSet := diffSet + {i} END;
- FOR i := 0 TO bitsToCheck - 1 DO
- IF (S.VAL( SET, adr.ipv6Adr[bytesToCheck] ) - diffSet) #
- (S.VAL( SET, prefix.ipv6Adr[bytesToCheck] ) - diffSet) THEN matches := FALSE
- END
- END
- END;
- RETURN matches
- END MatchPrefix;
- (** Checks if a string is a valid IPv4 address *)
- PROCEDURE IsValidIPv4Str( CONST ipString: ARRAY OF CHAR ): BOOLEAN;
- VAR i, j: LONGINT; ipNr: LONGINT;
- digits: ARRAY 4 OF CHAR;
- startClass: LONGINT;
- BEGIN
- i := 0;
- (* Class A *)
- WHILE (i < Strings.Length( ipString )) & (ipString[i] # '.') & (i < 3) DO digits[i] := ipString[i]; INC( i ) END;
- digits[i] := 0X;
- IF ipString[i] # '.' THEN RETURN FALSE END;
- (* Check if in digits are only numbers *)
- j := 0;
- WHILE digits[j] # 0X DO
- IF (ORD( digits[j] ) - ORD( "0" )) > 9 THEN RETURN FALSE END;
- INC( j );
- END;
- Strings.StrToInt( digits, ipNr );
- IF ipNr > 255 THEN RETURN FALSE END;
- (* Class B *)
- INC( i ); startClass := i;
- WHILE (i < Strings.Length( ipString )) & (ipString[i] # '.') & (i - startClass <= 3) DO
- digits[i - startClass] := ipString[i]; INC( i );
- END;
- digits[i - startClass] := 0X;
- IF ipString[i] # '.' THEN RETURN FALSE END;
- (* Check if in digits are only number *)
- j := 0;
- WHILE digits[j] # 0X DO
- IF (ORD( digits[j] ) - ORD( "0" )) > 9 THEN RETURN FALSE END;
- INC( j );
- END;
- Strings.StrToInt( digits, ipNr );
- IF ipNr > 255 THEN RETURN FALSE END;
- (* Class C *)
- INC( i ); startClass := i;
- WHILE (i < Strings.Length( ipString )) & (ipString[i] # '.') & (i - startClass <= 3) DO
- digits[i - startClass] := ipString[i]; INC( i );
- END;
- digits[i - startClass] := 0X;
- IF ipString[i] # '.' THEN RETURN FALSE END;
- (* Check if in digits are only number *)
- j := 0;
- WHILE digits[j] # 0X DO
- IF (ORD( digits[j] ) - ORD( "0" )) > 9 THEN RETURN FALSE END;
- INC( j );
- END;
- Strings.StrToInt( digits, ipNr );
- IF ipNr > 255 THEN RETURN FALSE END;
- (* Class D *)
- INC( i ); startClass := i;
- WHILE (i < Strings.Length( ipString )) & (i - startClass <= 3) DO digits[i - startClass] := ipString[i]; INC( i ) END;
- digits[i - startClass] := 0X;
- (* Check if in digits are only number *)
- j := 0;
- WHILE digits[j] # 0X DO
- IF (ORD( digits[j] ) - ORD( "0" )) > 9 THEN RETURN FALSE END;
- INC( j );
- END;
- Strings.StrToInt( digits, ipNr );
- IF ipNr > 255 THEN RETURN FALSE END;
- RETURN TRUE;
- END IsValidIPv4Str;
- (** Checks if a string is a valid IPv6 address *)
- PROCEDURE IsValidIPv6Str( ipString: ARRAY OF CHAR ): BOOLEAN;
- VAR i: LONGINT;
- state: LONGINT; (* -1: error *)
- charCount: LONGINT;
- ascD: LONGINT; ascH: LONGINT;
- dPointOcc: BOOLEAN;
- prefixLenArr: ARRAY 3 OF LONGINT;
- prefixLen: LONGINT;
- BEGIN
- i := 0; state := 1; dPointOcc := FALSE;
- Strings.UpperCase( ipString );
- WHILE (i < (LEN( ipString ) - 1)) & (ipString[i] # 0X) DO
- CASE state OF
- -1: RETURN FALSE;
- | 1:
- (* 0-9 & A-F *)
- ascD := ORD( ipString[i] ) - ORD( "0" );
- ascH := ORD( ipString[i] ) - ORD( "A" );
- IF ((ascD >= 0) & (ascD <= 9)) OR ((ascH >= 0) & (ascH <= 5)) THEN
- INC( charCount );
- IF charCount > 4 THEN state := -1 END;
- ELSIF ipString[i] = ":" THEN charCount := 0; state := 2;
- ELSIF ipString[i] = "/" THEN charCount := 0; state := 3;
- ELSE state := -1;
- END;
- | 2: ascD := ORD( ipString[i] ) - ORD( "0" );
- ascH := ORD( ipString[i] ) - ORD( "A" );
- IF ipString[i] = ":" THEN
- IF dPointOcc THEN state := -1 ELSE dPointOcc := TRUE; state := 4 END
- ELSIF ((ascD >= 0) & (ascD <= 9)) OR ((ascH >= 0) & (ascH <= 5)) THEN INC( charCount ); state := 1;
- ELSE state := -1;
- END;
- | 3: ascD := ORD( ipString[i] ) - ORD( "0" );
- IF ~((ascD >= 0) & (ascD <= 9)) THEN state := -1;
- ELSE
- IF charCount > 3 THEN state := -1 ELSE prefixLenArr[charCount] := ascD; INC( charCount ) END;
- END;
- | 4: ascD := ORD( ipString[i] ) - ORD( "0" );
- ascH := ORD( ipString[i] ) - ORD( "A" );
- IF ipString[i] = "/" THEN state := 3;
- ELSIF ((ascD >= 0) & (ascD <= 9)) OR ((ascH >= 0) & (ascH <= 5)) THEN INC( charCount ); state := 1;
- ELSE state := -1;
- END;
- ELSE
- END;
- INC( i );
- END;
- CASE state OF
- | 1: RETURN TRUE;
- | 3: IF charCount > 0 THEN prefixLen := 0;
- FOR i := 0 TO charCount - 1 DO prefixLen := prefixLen*10; INC( prefixLen, prefixLenArr[i] ) END;
- IF prefixLen <= 64 THEN RETURN TRUE ELSE RETURN FALSE END;
- ELSE RETURN FALSE;
- END;
- | 4: RETURN TRUE;
- ELSE
- RETURN FALSE;
- END;
- RETURN FALSE;
- END IsValidIPv6Str;
- (** Set IPv6 address to zero *)
- PROCEDURE SetIPv6AdrNil( adr: Adr );
- VAR i: LONGINT;
- BEGIN
- FOR i := 0 TO 15 DO adr.ipv6Adr[i] := 0X END;
- END SetIPv6AdrNil;
- (* 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
- (* NilAdr *)
- NilAdr.ipv4Adr := NilAdrIPv4;
- SetIPv6AdrNil( NilAdr );
- NilAdr.usedProtocol := NilAdrIdent;
- END IP.
-
|