Unix.IP.Mod 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647
  1. (* Aos, Copyright 2001, Pieter Muller, ETH Zurich *)
  2. MODULE IP; (** AUTHOR "pjm, mvt, eb, G.F."; PURPOSE "IP (v4 and v6)"; *)
  3. IMPORT S := SYSTEM, KernelLog, Strings, Network;
  4. CONST
  5. (** Error codes *)
  6. Ok* = 0;
  7. (** IP address constants *)
  8. NilAdrIPv4 = 0;
  9. (* Comparators for Adr.usedProtocols *)
  10. IPv4* = 4;
  11. IPv6* = 6;
  12. NilAdrIdent = -1; (* usedProtocol of NilAdrs *)
  13. MaxNofDNS = 4;
  14. TYPE
  15. Adr* = RECORD
  16. ipv4Adr*: LONGINT;
  17. ipv6Adr*: ARRAY 16 OF CHAR;
  18. usedProtocol*: LONGINT;
  19. data*: LONGINT;
  20. END;
  21. (** An IP Address.
  22. usedProtocol = 0: No protocol yet used
  23. usedProtocol = IPv4: IPv4 address stored in field ipv4Adr
  24. usedProtocol = IPv6: IPv6 address stored in field ipv6Adr
  25. data can be used to store additional informations. I.e. in IPv6 the
  26. prefix length is stored in the data field *)
  27. Packet* = POINTER TO ARRAY OF CHAR;
  28. Name* = ARRAY 128 OF CHAR; (** Name type for interface name *)
  29. ARPHandler* = PROCEDURE {DELEGATE} ( ip: Adr; complete: BOOLEAN;
  30. link: Network.LinkAdr;
  31. size, sendTime, updateTime, updateDate, hash: LONGINT);
  32. Interface* = OBJECT
  33. (*! unused in UnixAos, included only for interface compatibility
  34. mostly a dummy, only 'localAdr' contains valid data in UnixAos !! *)
  35. VAR
  36. (** IP addresses of this interface. *)
  37. localAdr-, maskAdr-, gatewayAdr-, subnetAdr-, broadAdr-: Adr;
  38. (** name of the interface *)
  39. name-: Name;
  40. (** Device that the interface belongs to *)
  41. dev-: Network.LinkDevice;
  42. (** DNS server list - can be used by DNS, not used in IP itself *)
  43. DNS-: ARRAY MaxNofDNS OF Adr; (* DNS server list *)
  44. DNScount-: LONGINT; (* number of DNS servers in list *)
  45. (* interface *)
  46. next*: Interface; (* next pointer for interface list *)
  47. closed-: BOOLEAN; (* is interface already closed? *)
  48. protocol-: LONGINT;
  49. (* Interface for IPv4 or IPv6?. Only used by IP otherwise use dynamic type checking! *)
  50. PROCEDURE & Init*( addr: Adr );
  51. BEGIN
  52. localAdr := addr;
  53. name := "dummy";
  54. END Init;
  55. END Interface;
  56. InterfaceHandler* = PROCEDURE {DELEGATE} (int: Interface);
  57. VAR
  58. (* IP *)
  59. NilAdr*: Adr; (* To check if an IP address is NIL use IsNilAdr instead *)
  60. preferredProtocol*: LONGINT; (* Preferred IP protocol *)
  61. (** Is address not yet specified *)
  62. PROCEDURE IsNilAdr*( adr: Adr ): BOOLEAN;
  63. VAR isNil: BOOLEAN; i: LONGINT;
  64. BEGIN
  65. CASE adr.usedProtocol OF
  66. | IPv4: RETURN (adr.ipv4Adr = NilAdrIPv4)
  67. | IPv6: isNil := TRUE; i := 0;
  68. WHILE ((i < 16) & isNil) DO
  69. IF adr.ipv6Adr[i] # 0X THEN isNil := FALSE END;
  70. INC( i );
  71. END;
  72. RETURN isNil;
  73. | NilAdrIdent:
  74. RETURN TRUE;
  75. ELSE
  76. RETURN TRUE;
  77. END;
  78. END IsNilAdr;
  79. (* Checks if two addresses are equal *)
  80. PROCEDURE AdrsEqual*( adr1, adr2: Adr ): BOOLEAN;
  81. VAR equal: BOOLEAN; i: LONGINT;
  82. BEGIN
  83. IF adr1.usedProtocol # adr2.usedProtocol THEN RETURN FALSE END;
  84. CASE adr1.usedProtocol OF
  85. | IPv4: IF adr1.ipv4Adr = adr2.ipv4Adr THEN RETURN TRUE END;
  86. | IPv6: equal := TRUE; i := 0;
  87. WHILE ((i < 16) & equal) DO
  88. IF adr1.ipv6Adr[i] # adr2.ipv6Adr[i] THEN equal := FALSE END;
  89. INC( i );
  90. END;
  91. IF adr1.data # adr2.data THEN equal := FALSE END;
  92. RETURN equal;
  93. | NilAdrIdent:
  94. (* both addresses NIL therefore equal *)
  95. IF adr2.usedProtocol = NilAdrIdent THEN RETURN TRUE ELSE RETURN FALSE END
  96. ELSE RETURN FALSE
  97. END;
  98. RETURN FALSE
  99. END AdrsEqual;
  100. (** Convert a dotted-decimal string to an ip address. Return NilAdr on failure. *)
  101. PROCEDURE StrToAdr*( ipString: ARRAY OF CHAR ): Adr;
  102. VAR retAdr: Adr; i, j, x: LONGINT;
  103. adr: ARRAY 4 OF CHAR;
  104. ok: BOOLEAN;
  105. charCount: LONGINT; (* ipv6: number of character between two : *)
  106. ipv6AdrPart: ARRAY 6 OF CHAR; (* two bytes of an IPv6 address *)
  107. ipv6AdrRight: ARRAY 16 OF CHAR; (* right part of an IPv6 address; after :: *)
  108. hexToChar: ARRAY 3 OF CHAR;
  109. leftParts: LONGINT; (* number of bytes before :: *)
  110. rightParts: LONGINT; (* number of bytes after :: *)
  111. val: LONGINT; res: WORD;
  112. state: LONGINT; (* state of the FSM look at the eof for more info *)
  113. dPointOcc: BOOLEAN; (* double point occured *)
  114. prefixVal: LONGINT;
  115. (* compute a subpart (two bytes) of a IPv6 address; subpart:=between two : *)
  116. PROCEDURE ComputeIPv6Part( ): BOOLEAN;
  117. BEGIN
  118. CASE charCount OF
  119. | 0: RETURN TRUE;
  120. | 1, 2: IF dPointOcc THEN ipv6AdrRight[rightParts] := 0X; INC( rightParts );
  121. ELSE retAdr.ipv6Adr[leftParts] := 0X; INC( leftParts );
  122. END;
  123. Strings.HexStrToInt( ipv6AdrPart, val, res );
  124. IF res = Strings.Ok THEN
  125. IF dPointOcc THEN ipv6AdrRight[rightParts] := CHR( val ); INC( rightParts );
  126. ELSE retAdr.ipv6Adr[leftParts] := CHR( val ); INC( leftParts );
  127. END;
  128. ELSE RETURN FALSE
  129. END;
  130. | 3: hexToChar[0] := ipv6AdrPart[0]; hexToChar[1] := 0X;
  131. Strings.HexStrToInt( hexToChar, val, res );
  132. IF res = Strings.Ok THEN
  133. IF dPointOcc THEN ipv6AdrRight[rightParts] := CHR( val ); INC( rightParts );
  134. ELSE retAdr.ipv6Adr[leftParts] := CHR( val ); INC( leftParts );
  135. END;
  136. ELSE RETURN FALSE
  137. END;
  138. ipv6AdrPart[0] := "0"; Strings.HexStrToInt( ipv6AdrPart, val, res );
  139. IF res = Strings.Ok THEN
  140. IF dPointOcc THEN ipv6AdrRight[rightParts] := CHR( val ); INC( rightParts );
  141. ELSE retAdr.ipv6Adr[leftParts] := CHR( val ); INC( leftParts );
  142. END;
  143. ELSE RETURN FALSE
  144. END;
  145. | 4: hexToChar[0] := ipv6AdrPart[0]; hexToChar[1] := ipv6AdrPart[1]; hexToChar[2] := 0X;
  146. Strings.HexStrToInt( hexToChar, val, res );
  147. IF res = Strings.Ok THEN
  148. IF dPointOcc THEN ipv6AdrRight[rightParts] := CHR( val ); INC( rightParts );
  149. ELSE retAdr.ipv6Adr[leftParts] := CHR( val ); INC( leftParts );
  150. END;
  151. ELSE RETURN FALSE
  152. END;
  153. ipv6AdrPart[0] := "0"; ipv6AdrPart[1] := "0"; Strings.HexStrToInt( ipv6AdrPart, val, res );
  154. IF res = Strings.Ok THEN
  155. IF dPointOcc THEN ipv6AdrRight[rightParts] := CHR( val ); INC( rightParts );
  156. ELSE retAdr.ipv6Adr[leftParts] := CHR( val ); INC( leftParts );
  157. END;
  158. ELSE RETURN FALSE
  159. END;
  160. ELSE RETURN FALSE;
  161. END;
  162. charCount := 0; RETURN TRUE;
  163. END ComputeIPv6Part;
  164. BEGIN
  165. retAdr := NilAdr;
  166. IF IsValidIPv4Str( ipString ) THEN
  167. (* Return an ipv4 address *)
  168. i := 0; j := 0; x := -1; ok := FALSE;
  169. LOOP
  170. IF (ipString[i] = ".") OR (ipString[i] = 0X) THEN
  171. IF (x < 0) OR (x > 255) OR (j = 4) THEN EXIT END;
  172. adr[j] := CHR( x );
  173. IF ipString[i] = 0X THEN ok := (j = 3); EXIT END;
  174. x := -1; INC( i ); INC( j )
  175. ELSIF (ipString[i] >= "0") & (ipString[i] <= "9") THEN
  176. IF x = -1 THEN x := 0 END;
  177. x := x*10 + (ORD( ipString[i] ) - ORD( "0" )); INC( i )
  178. ELSE EXIT
  179. END
  180. END;
  181. IF ok THEN retAdr.ipv4Adr := S.VAL( LONGINT, adr ); retAdr.usedProtocol := IPv4; RETURN retAdr;
  182. ELSE RETURN NilAdr;
  183. END
  184. ELSIF IsValidIPv6Str( ipString ) THEN
  185. i := 0; state := 1; charCount := 0; dPointOcc := FALSE;
  186. retAdr.usedProtocol := 6; retAdr.ipv4Adr := NilAdrIPv4;
  187. i := 0; j := 0; charCount := 0; leftParts := 0; rightParts := 0; prefixVal := 0;
  188. Strings.UpperCase( ipString );
  189. WHILE (i < (LEN( ipString ) - 1)) & (ipString[i] # 0X) DO
  190. CASE state OF (* Using the same FSM as IsValidIPv6Str *)
  191. | -1: (* Error state Should never happen, is checked by IsValidIPv6Str() *)
  192. RETURN NilAdr;
  193. | 1: (* reading two blocks of two bytes of 0-9\A-F *)
  194. IF ipString[i] = ":" THEN
  195. ipv6AdrPart[charCount] := 0X;
  196. IF ~ComputeIPv6Part() THEN RETURN NilAdr END;
  197. state := 2;
  198. ELSIF ipString[i] = "/" THEN
  199. ipv6AdrPart[charCount] := 0X;
  200. IF ~ComputeIPv6Part() THEN RETURN NilAdr END;
  201. state := 3;
  202. ELSE (* 0-9, A-F *)
  203. ipv6AdrPart[charCount] := ipString[i]; INC( charCount );
  204. END;
  205. | 2: (* a : occured *)
  206. IF ipString[i] = ":" THEN dPointOcc := TRUE; state := 4
  207. ELSE (* 0-9, A-F *)
  208. state := 1; charCount := 0; ipv6AdrPart[charCount] := ipString[i]; INC( charCount );
  209. END;
  210. | 3: (* prefix will follow *)
  211. prefixVal := (prefixVal*10) + (ORD( ipString[i] ) - ORD( "0" ));
  212. | 4: (* A :: occured *)
  213. IF ipString[i] = "/" THEN state := 3
  214. ELSE
  215. IF ~ComputeIPv6Part() THEN RETURN NilAdr END;
  216. (* 0-9, A-F *)
  217. state := 1; charCount := 0; ipv6AdrPart[charCount] := ipString[i]; INC( charCount )
  218. END;
  219. ELSE
  220. END;
  221. INC( i );
  222. END;
  223. ipv6AdrPart[charCount] := 0X;
  224. IF charCount # 0 THEN
  225. IF ~ComputeIPv6Part() THEN RETURN NilAdr END;
  226. END;
  227. IF dPointOcc THEN
  228. (* fill 0X for :: *)
  229. FOR i := leftParts TO ((LEN( retAdr.ipv6Adr ) - 1) - rightParts) DO retAdr.ipv6Adr[i] := 0X END;
  230. (* fill part behind :: *)
  231. FOR i := 0 TO (rightParts - 1) DO
  232. retAdr.ipv6Adr[(LEN( retAdr.ipv6Adr ) - rightParts) + i] := ipv6AdrRight[i]
  233. END;
  234. END;
  235. IF prefixVal > 64 THEN RETURN NilAdr END;
  236. retAdr.data := prefixVal; RETURN retAdr;
  237. END;
  238. RETURN NilAdr;
  239. END StrToAdr;
  240. (** Convert an IP address to a dotted-decimal string. *)
  241. PROCEDURE AdrToStr*( adr: Adr; VAR string: ARRAY OF CHAR );
  242. VAR i, j, x: LONGINT;
  243. a: ARRAY 4 OF CHAR;
  244. val: LONGINT;
  245. hexToStr: ARRAY 5 OF CHAR;
  246. prefixLenStr: ARRAY 64 OF CHAR;
  247. maxZeroRow: LONGINT; currentZeroRow: LONGINT;
  248. maxZeroStart: LONGINT; currentZeroStart: LONGINT;
  249. lastZero: BOOLEAN; lastDPoint: BOOLEAN; countEnded: BOOLEAN;
  250. BEGIN
  251. CASE adr.usedProtocol OF
  252. | IPv4:
  253. Network.Put4( a, 0, adr.ipv4Adr );
  254. i := 0;
  255. FOR j := 0 TO 3 DO
  256. x := ORD( a[j] );
  257. IF x >= 100 THEN string[i] := CHR( ORD( "0" ) + x DIV 100 ); INC( i ) END;
  258. IF x >= 10 THEN string[i] := CHR( ORD( "0" ) + x DIV 10 MOD 10 ); INC( i ) END;
  259. string[i] := CHR( ORD( "0" ) + x MOD 10 ); INC( i );
  260. IF j = 3 THEN string[i] := 0X ELSE string[i] := "." END;
  261. INC( i )
  262. END
  263. | IPv6:
  264. FOR i := 0 TO LEN( adr.ipv6Adr ) - 1 BY 2 DO
  265. (* simple version *)
  266. val := ORD( adr.ipv6Adr[i] )*256;
  267. val := val + ORD( adr.ipv6Adr[i + 1] );
  268. Strings.IntToHexStr( val, 3, hexToStr );
  269. (* Delete leading zeros *)
  270. WHILE (hexToStr[0] = "0") & (hexToStr[1] # 0X) DO Strings.Delete( hexToStr, 0, 1 ) END;
  271. Strings.Append( string, hexToStr );
  272. IF i # (LEN( adr.ipv6Adr ) - 2) THEN Strings.Append( string, ":" ) END;
  273. END;
  274. (* replace longest row of zeros with :: *)
  275. maxZeroRow := 0; currentZeroRow := 0;
  276. maxZeroStart := 0; currentZeroStart := 0; i := 0;
  277. lastZero := FALSE; lastDPoint := TRUE; countEnded := TRUE;
  278. WHILE string[i] # 0X DO
  279. IF string[i] = "0" THEN
  280. IF lastDPoint THEN
  281. INC( currentZeroRow ); lastZero := TRUE; lastDPoint := FALSE;
  282. IF countEnded THEN currentZeroStart := i; countEnded := FALSE END;
  283. END;
  284. ELSIF string[i] = ":" THEN
  285. lastDPoint := TRUE;
  286. IF lastZero THEN lastZero := FALSE END;
  287. ELSE
  288. IF lastDPoint THEN
  289. lastDPoint := FALSE; countEnded := TRUE;
  290. IF currentZeroRow > maxZeroRow THEN
  291. maxZeroRow := currentZeroRow; maxZeroStart := currentZeroStart;
  292. END;
  293. END;
  294. END;
  295. INC( i );
  296. END;
  297. IF ~countEnded THEN
  298. IF currentZeroRow > maxZeroRow THEN
  299. maxZeroRow := currentZeroRow; maxZeroStart := currentZeroStart;
  300. END;
  301. END;
  302. IF maxZeroRow # 0 THEN
  303. (* write a :: *)
  304. IF maxZeroStart = 0 THEN
  305. string[0] := ":"; i := 1;
  306. WHILE ((string[i] # 0X) & ~((string[i] # "0") & (string[i] # ":"))) DO INC( i ) END;
  307. IF string[i] = 0X THEN COPY( "::", string ) ELSE Strings.Delete( string, 1, i - 2 ) END;
  308. ELSE
  309. i := maxZeroStart;
  310. WHILE ((string[i] = "0") OR (string[i] = ":")) DO INC( i ) END;
  311. IF string[i] = 0X THEN string[maxZeroStart] := ":"; string[maxZeroStart + 1] := 0X;
  312. ELSE Strings.Delete( string, maxZeroStart, i - maxZeroStart - 1 );
  313. END;
  314. END;
  315. END;
  316. IF adr.data # 0 THEN (* write prefix *)
  317. Strings.IntToStr( adr.data, prefixLenStr ); Strings.Append( string, "/" );
  318. Strings.Append( string, prefixLenStr );
  319. END;
  320. ELSE
  321. IF IsNilAdr( adr ) THEN string[0] := 0X END;
  322. END;
  323. END AdrToStr;
  324. (** Convert a IP address from an array [ofs..ofs+x] to an
  325. Adr-type variable.
  326. Example for IPv4:
  327. If the LSB (least significant byte) is stored the the beginning [ofs],
  328. LSBfirst must be set to TRUE.
  329. (address "a.b.c.d" is stored as [d,c,b,a])
  330. If the LSB is stored at the end [ofs+3], LSBfirst must be set to FALSE.
  331. (address "a.b.c.d" is stored as [a,b,c,d])
  332. *)
  333. PROCEDURE ArrayToAdr*( CONST arr: ARRAY OF CHAR; ofs, protocol: LONGINT; LSBfirst: BOOLEAN ): Adr;
  334. VAR adr: Adr; i, swapTemp: LONGINT;
  335. BEGIN
  336. ASSERT( (protocol = 4) OR (protocol = 6) );
  337. IF protocol = IPv4 THEN (* index check *)
  338. IF ~(ofs + 4 <= LEN( arr )) THEN RETURN NilAdr END;
  339. S.MOVE( ADDRESSOF( arr[ofs] ), ADDRESSOF( adr.ipv4Adr ), 4 );
  340. IF LSBfirst THEN SwapEndian( adr.ipv4Adr ) END;
  341. adr.usedProtocol := IPv4;
  342. ELSIF protocol = IPv6 THEN
  343. IF ~(ofs + 16 <= LEN( arr )) THEN RETURN NilAdr END;
  344. S.MOVE( ADDRESSOF( arr[ofs] ), ADDRESSOF( adr.ipv6Adr ), 16 );
  345. IF LSBfirst THEN
  346. FOR i := 0 TO 3 DO
  347. S.MOVE( ADDRESSOF( adr.ipv6Adr[i*4] ), ADDRESSOF( swapTemp ), 4 );
  348. SwapEndian( swapTemp );
  349. S.MOVE( ADDRESSOF( swapTemp ), ADDRESSOF( adr.ipv6Adr[i*4] ), 4 );
  350. END;
  351. END;
  352. adr.usedProtocol := IPv6;
  353. ELSE
  354. RETURN NilAdr;
  355. END;
  356. RETURN adr;
  357. END ArrayToAdr;
  358. (** Convert an Adr-type variable into an array [ofs..ofs+x]
  359. Example in IPv4:
  360. If the LSB (least significant byte) should be stored the the
  361. beginning [ofs], LSBfirst must be set to TRUE.
  362. (address "a.b.c.d" is stored as [d,c,b,a])
  363. If the LSB should be stored at the end [ofs+3], LSBfirst must be set to FALSE.
  364. (address "a.b.c.d" is stored as [a,b,c,d])
  365. *)
  366. PROCEDURE AdrToArray*( adr: Adr; VAR arr: ARRAY OF CHAR; ofs: LONGINT; LSBfirst: BOOLEAN );
  367. VAR tempAdr: Adr; i, swapTemp: LONGINT;
  368. BEGIN
  369. tempAdr := adr;
  370. CASE adr.usedProtocol OF
  371. | IPv4:
  372. IF ~(ofs + 4 <= LEN( arr )) THEN tempAdr := NilAdr END;
  373. IF LSBfirst THEN SwapEndian( tempAdr.ipv4Adr ) END;
  374. S.MOVE( ADDRESSOF( tempAdr.ipv4Adr ), ADDRESSOF( arr[ofs] ), 4 );
  375. | IPv6:
  376. IF ~(ofs + 16 <= LEN( arr )) THEN tempAdr := NilAdr END;
  377. IF LSBfirst THEN
  378. FOR i := 0 TO 3 DO
  379. S.MOVE( ADDRESSOF( tempAdr.ipv6Adr[i*4] ), ADDRESSOF( swapTemp ), 4 );
  380. SwapEndian( swapTemp );
  381. S.MOVE( ADDRESSOF( swapTemp ), ADDRESSOF( tempAdr.ipv6Adr[i*4] ), 4 );
  382. END;
  383. END;
  384. S.MOVE( ADDRESSOF( adr.ipv6Adr ), ADDRESSOF( arr[ofs] ), 16 );
  385. ELSE
  386. END;
  387. END AdrToArray;
  388. (** Aos command: Output statistics and configuration of all installed interfaces. *)
  389. PROCEDURE IPConfig*( par: ANY ): ANY;
  390. BEGIN
  391. KernelLog.String( "Interfaces:" ); KernelLog.Ln; RETURN NIL;
  392. END IPConfig;
  393. (* Return TRUE if adr matches the prefix *)
  394. PROCEDURE MatchPrefix*( adr: Adr; prefix: Adr ): BOOLEAN;
  395. VAR
  396. bytesToCheck: LONGINT; bitsToCheck: LONGINT; i: LONGINT; matches: BOOLEAN; diffSet: SET;
  397. BEGIN
  398. matches := TRUE;
  399. bytesToCheck := prefix.data DIV 8; bitsToCheck := prefix.data MOD 8;
  400. FOR i := 0 TO bytesToCheck - 1 DO
  401. IF adr.ipv6Adr[i] # prefix.ipv6Adr[i] THEN matches := FALSE END;
  402. END;
  403. IF bitsToCheck # 0 THEN
  404. diffSet := {};
  405. FOR i := 0 TO 8 - bitsToCheck - 1 DO diffSet := diffSet + {i} END;
  406. FOR i := 0 TO bitsToCheck - 1 DO
  407. IF (S.VAL( SET, adr.ipv6Adr[bytesToCheck] ) - diffSet) #
  408. (S.VAL( SET, prefix.ipv6Adr[bytesToCheck] ) - diffSet) THEN matches := FALSE
  409. END
  410. END
  411. END;
  412. RETURN matches
  413. END MatchPrefix;
  414. (** Checks if a string is a valid IPv4 address *)
  415. PROCEDURE IsValidIPv4Str( CONST ipString: ARRAY OF CHAR ): BOOLEAN;
  416. VAR i, j: LONGINT; ipNr: LONGINT;
  417. digits: ARRAY 4 OF CHAR;
  418. startClass: LONGINT;
  419. BEGIN
  420. i := 0;
  421. (* Class A *)
  422. WHILE (i < Strings.Length( ipString )) & (ipString[i] # '.') & (i < 3) DO digits[i] := ipString[i]; INC( i ) END;
  423. digits[i] := 0X;
  424. IF ipString[i] # '.' THEN RETURN FALSE END;
  425. (* Check if in digits are only numbers *)
  426. j := 0;
  427. WHILE digits[j] # 0X DO
  428. IF (ORD( digits[j] ) - ORD( "0" )) > 9 THEN RETURN FALSE END;
  429. INC( j );
  430. END;
  431. Strings.StrToInt( digits, ipNr );
  432. IF ipNr > 255 THEN RETURN FALSE END;
  433. (* Class B *)
  434. INC( i ); startClass := i;
  435. WHILE (i < Strings.Length( ipString )) & (ipString[i] # '.') & (i - startClass <= 3) DO
  436. digits[i - startClass] := ipString[i]; INC( i );
  437. END;
  438. digits[i - startClass] := 0X;
  439. IF ipString[i] # '.' THEN RETURN FALSE END;
  440. (* Check if in digits are only number *)
  441. j := 0;
  442. WHILE digits[j] # 0X DO
  443. IF (ORD( digits[j] ) - ORD( "0" )) > 9 THEN RETURN FALSE END;
  444. INC( j );
  445. END;
  446. Strings.StrToInt( digits, ipNr );
  447. IF ipNr > 255 THEN RETURN FALSE END;
  448. (* Class C *)
  449. INC( i ); startClass := i;
  450. WHILE (i < Strings.Length( ipString )) & (ipString[i] # '.') & (i - startClass <= 3) DO
  451. digits[i - startClass] := ipString[i]; INC( i );
  452. END;
  453. digits[i - startClass] := 0X;
  454. IF ipString[i] # '.' THEN RETURN FALSE END;
  455. (* Check if in digits are only number *)
  456. j := 0;
  457. WHILE digits[j] # 0X DO
  458. IF (ORD( digits[j] ) - ORD( "0" )) > 9 THEN RETURN FALSE END;
  459. INC( j );
  460. END;
  461. Strings.StrToInt( digits, ipNr );
  462. IF ipNr > 255 THEN RETURN FALSE END;
  463. (* Class D *)
  464. INC( i ); startClass := i;
  465. WHILE (i < Strings.Length( ipString )) & (i - startClass <= 3) DO digits[i - startClass] := ipString[i]; INC( i ) END;
  466. digits[i - startClass] := 0X;
  467. (* Check if in digits are only number *)
  468. j := 0;
  469. WHILE digits[j] # 0X DO
  470. IF (ORD( digits[j] ) - ORD( "0" )) > 9 THEN RETURN FALSE END;
  471. INC( j );
  472. END;
  473. Strings.StrToInt( digits, ipNr );
  474. IF ipNr > 255 THEN RETURN FALSE END;
  475. RETURN TRUE;
  476. END IsValidIPv4Str;
  477. (** Checks if a string is a valid IPv6 address *)
  478. PROCEDURE IsValidIPv6Str( ipString: ARRAY OF CHAR ): BOOLEAN;
  479. VAR i: LONGINT;
  480. state: LONGINT; (* -1: error *)
  481. charCount: LONGINT;
  482. ascD: LONGINT; ascH: LONGINT;
  483. dPointOcc: BOOLEAN;
  484. prefixLenArr: ARRAY 3 OF LONGINT;
  485. prefixLen: LONGINT;
  486. BEGIN
  487. i := 0; state := 1; dPointOcc := FALSE;
  488. Strings.UpperCase( ipString );
  489. WHILE (i < (LEN( ipString ) - 1)) & (ipString[i] # 0X) DO
  490. CASE state OF
  491. -1: RETURN FALSE;
  492. | 1:
  493. (* 0-9 & A-F *)
  494. ascD := ORD( ipString[i] ) - ORD( "0" );
  495. ascH := ORD( ipString[i] ) - ORD( "A" );
  496. IF ((ascD >= 0) & (ascD <= 9)) OR ((ascH >= 0) & (ascH <= 5)) THEN
  497. INC( charCount );
  498. IF charCount > 4 THEN state := -1 END;
  499. ELSIF ipString[i] = ":" THEN charCount := 0; state := 2;
  500. ELSIF ipString[i] = "/" THEN charCount := 0; state := 3;
  501. ELSE state := -1;
  502. END;
  503. | 2: ascD := ORD( ipString[i] ) - ORD( "0" );
  504. ascH := ORD( ipString[i] ) - ORD( "A" );
  505. IF ipString[i] = ":" THEN
  506. IF dPointOcc THEN state := -1 ELSE dPointOcc := TRUE; state := 4 END
  507. ELSIF ((ascD >= 0) & (ascD <= 9)) OR ((ascH >= 0) & (ascH <= 5)) THEN INC( charCount ); state := 1;
  508. ELSE state := -1;
  509. END;
  510. | 3: ascD := ORD( ipString[i] ) - ORD( "0" );
  511. IF ~((ascD >= 0) & (ascD <= 9)) THEN state := -1;
  512. ELSE
  513. IF charCount > 3 THEN state := -1 ELSE prefixLenArr[charCount] := ascD; INC( charCount ) END;
  514. END;
  515. | 4: ascD := ORD( ipString[i] ) - ORD( "0" );
  516. ascH := ORD( ipString[i] ) - ORD( "A" );
  517. IF ipString[i] = "/" THEN state := 3;
  518. ELSIF ((ascD >= 0) & (ascD <= 9)) OR ((ascH >= 0) & (ascH <= 5)) THEN INC( charCount ); state := 1;
  519. ELSE state := -1;
  520. END;
  521. ELSE
  522. END;
  523. INC( i );
  524. END;
  525. CASE state OF
  526. | 1: RETURN TRUE;
  527. | 3: IF charCount > 0 THEN prefixLen := 0;
  528. FOR i := 0 TO charCount - 1 DO prefixLen := prefixLen*10; INC( prefixLen, prefixLenArr[i] ) END;
  529. IF prefixLen <= 64 THEN RETURN TRUE ELSE RETURN FALSE END;
  530. ELSE RETURN FALSE;
  531. END;
  532. | 4: RETURN TRUE;
  533. ELSE
  534. RETURN FALSE;
  535. END;
  536. RETURN FALSE;
  537. END IsValidIPv6Str;
  538. (** Set IPv6 address to zero *)
  539. PROCEDURE SetIPv6AdrNil( adr: Adr );
  540. VAR i: LONGINT;
  541. BEGIN
  542. FOR i := 0 TO 15 DO adr.ipv6Adr[i] := 0X END;
  543. END SetIPv6AdrNil;
  544. (* Swap internal representation of an IP address from big to little endian or vice versa. *)
  545. PROCEDURE -SwapEndian( VAR adr: LONGINT );
  546. CODE
  547. #IF I386 THEN
  548. POP EAX
  549. MOV ECX, [EAX]
  550. XCHG CL, CH
  551. ROL ECX, 16
  552. XCHG CL, CH
  553. MOV [EAX], ECX
  554. #ELSIF AMD64 THEN
  555. POP RAX
  556. MOV ECX, [RAX]
  557. XCHG CL, CH
  558. ROL ECX, 16
  559. XCHG CL, CH
  560. MOV [RAX], ECX
  561. #ELSE
  562. unimplemented
  563. #END
  564. END SwapEndian;
  565. BEGIN
  566. (* NilAdr *)
  567. NilAdr.ipv4Adr := NilAdrIPv4;
  568. SetIPv6AdrNil( NilAdr );
  569. NilAdr.usedProtocol := NilAdrIdent;
  570. END IP.