synaip.pas 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417
  1. {==============================================================================|
  2. | Project : Ararat Synapse | 001.002.000 |
  3. |==============================================================================|
  4. | Content: IP address support procedures and functions |
  5. |==============================================================================|
  6. | Copyright (c)2006-2009, Lukas Gebauer |
  7. | All rights reserved. |
  8. | |
  9. | Redistribution and use in source and binary forms, with or without |
  10. | modification, are permitted provided that the following conditions are met: |
  11. | |
  12. | Redistributions of source code must retain the above copyright notice, this |
  13. | list of conditions and the following disclaimer. |
  14. | |
  15. | Redistributions in binary form must reproduce the above copyright notice, |
  16. | this list of conditions and the following disclaimer in the documentation |
  17. | and/or other materials provided with the distribution. |
  18. | |
  19. | Neither the name of Lukas Gebauer nor the names of its contributors may |
  20. | be used to endorse or promote products derived from this software without |
  21. | specific prior written permission. |
  22. | |
  23. | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" |
  24. | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
  25. | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
  26. | ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR |
  27. | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
  28. | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR |
  29. | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER |
  30. | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
  31. | LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
  32. | OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH |
  33. | DAMAGE. |
  34. |==============================================================================|
  35. | The Initial Developer of the Original Code is Lukas Gebauer (Czech Republic).|
  36. | Portions created by Lukas Gebauer are Copyright (c) 2006-2008. |
  37. | All Rights Reserved. |
  38. |==============================================================================|
  39. | Contributor(s): |
  40. |==============================================================================|
  41. | History: see HISTORY.HTM from distribution package |
  42. | (Found at URL: http://www.ararat.cz/synapse/) |
  43. |==============================================================================}
  44. {:@abstract(IP adress support procedures and functions)}
  45. {$IFDEF FPC}
  46. {$MODE DELPHI}
  47. {$ENDIF}
  48. {$Q-}
  49. {$R-}
  50. {$H+}
  51. unit synaip;
  52. interface
  53. uses
  54. SysUtils, SynaUtil;
  55. type
  56. {:binary form of IPv6 adress (for string conversion routines)}
  57. TIp6Bytes = array [0..15] of Byte;
  58. {:binary form of IPv6 adress (for string conversion routines)}
  59. TIp6Words = array [0..7] of Word;
  60. {:Returns @TRUE, if "Value" is a valid IPv4 address. Cannot be a symbolic Name!}
  61. function IsIP(const Value: string): Boolean;
  62. {:Returns @TRUE, if "Value" is a valid IPv6 address. Cannot be a symbolic Name!}
  63. function IsIP6(const Value: string): Boolean;
  64. {:Returns a string with the "Host" ip address converted to binary form.}
  65. function IPToID(Host: string): Ansistring;
  66. {:Convert IPv6 address from their string form to binary byte array.}
  67. function StrToIp6(value: string): TIp6Bytes;
  68. {:Convert IPv6 address from binary byte array to string form.}
  69. function Ip6ToStr(value: TIp6Bytes): string;
  70. {:Convert IPv4 address from their string form to binary.}
  71. function StrToIp(value: string): integer;
  72. {:Convert IPv4 address from binary to string form.}
  73. function IpToStr(value: integer): string;
  74. {:Convert IPv4 address to reverse form.}
  75. function ReverseIP(Value: AnsiString): AnsiString;
  76. {:Convert IPv6 address to reverse form.}
  77. function ReverseIP6(Value: AnsiString): AnsiString;
  78. {:Expand short form of IPv6 address to long form.}
  79. function ExpandIP6(Value: AnsiString): AnsiString;
  80. implementation
  81. {==============================================================================}
  82. function IsIP(const Value: string): Boolean;
  83. var
  84. TempIP: string;
  85. function ByteIsOk(const Value: string): Boolean;
  86. var
  87. x, n: integer;
  88. begin
  89. x := StrToIntDef(Value, -1);
  90. Result := (x >= 0) and (x < 256);
  91. // X may be in correct range, but value still may not be correct value!
  92. // i.e. "$80"
  93. if Result then
  94. for n := 1 to length(Value) do
  95. if not (Value[n] in ['0'..'9']) then
  96. begin
  97. Result := False;
  98. Break;
  99. end;
  100. end;
  101. begin
  102. TempIP := Value;
  103. Result := False;
  104. if not ByteIsOk(Fetch(TempIP, '.')) then
  105. Exit;
  106. if not ByteIsOk(Fetch(TempIP, '.')) then
  107. Exit;
  108. if not ByteIsOk(Fetch(TempIP, '.')) then
  109. Exit;
  110. if ByteIsOk(TempIP) then
  111. Result := True;
  112. end;
  113. {==============================================================================}
  114. function IsIP6(const Value: string): Boolean;
  115. var
  116. TempIP: string;
  117. s,t: string;
  118. x: integer;
  119. partcount: integer;
  120. zerocount: integer;
  121. First: Boolean;
  122. begin
  123. TempIP := Value;
  124. Result := False;
  125. if Value = '::' then
  126. begin
  127. Result := True;
  128. Exit;
  129. end;
  130. partcount := 0;
  131. zerocount := 0;
  132. First := True;
  133. while tempIP <> '' do
  134. begin
  135. s := fetch(TempIP, ':');
  136. if not(First) and (s = '') then
  137. Inc(zerocount);
  138. First := False;
  139. if zerocount > 1 then
  140. break;
  141. Inc(partCount);
  142. if s = '' then
  143. Continue;
  144. if partCount > 8 then
  145. break;
  146. if tempIP = '' then
  147. begin
  148. t := SeparateRight(s, '%');
  149. s := SeparateLeft(s, '%');
  150. x := StrToIntDef('$' + t, -1);
  151. if (x < 0) or (x > $ffff) then
  152. break;
  153. end;
  154. x := StrToIntDef('$' + s, -1);
  155. if (x < 0) or (x > $ffff) then
  156. break;
  157. if tempIP = '' then
  158. if not((PartCount = 1) and (ZeroCount = 0)) then
  159. Result := True;
  160. end;
  161. end;
  162. {==============================================================================}
  163. function IPToID(Host: string): Ansistring;
  164. var
  165. s: string;
  166. i, x: Integer;
  167. begin
  168. Result := '';
  169. for x := 0 to 3 do
  170. begin
  171. s := Fetch(Host, '.');
  172. i := StrToIntDef(s, 0);
  173. Result := Result + Chr(i);
  174. end;
  175. end;
  176. {==============================================================================}
  177. function StrToIp(value: string): integer;
  178. var
  179. s: string;
  180. i, x: Integer;
  181. begin
  182. Result := 0;
  183. for x := 0 to 3 do
  184. begin
  185. s := Fetch(value, '.');
  186. i := StrToIntDef(s, 0);
  187. Result := (256 * Result) + i;
  188. end;
  189. end;
  190. {==============================================================================}
  191. function IpToStr(value: integer): string;
  192. var
  193. x1, x2: word;
  194. y1, y2: byte;
  195. begin
  196. Result := '';
  197. x1 := value shr 16;
  198. x2 := value and $FFFF;
  199. y1 := x1 div $100;
  200. y2 := x1 mod $100;
  201. Result := inttostr(y1) + '.' + inttostr(y2) + '.';
  202. y1 := x2 div $100;
  203. y2 := x2 mod $100;
  204. Result := Result + inttostr(y1) + '.' + inttostr(y2);
  205. end;
  206. {==============================================================================}
  207. function ExpandIP6(Value: AnsiString): AnsiString;
  208. var
  209. n: integer;
  210. s: ansistring;
  211. x: integer;
  212. begin
  213. Result := '';
  214. if value = '' then
  215. exit;
  216. x := countofchar(value, ':');
  217. if x > 7 then
  218. exit;
  219. if value[1] = ':' then
  220. value := '0' + value;
  221. if value[length(value)] = ':' then
  222. value := value + '0';
  223. x := 8 - x;
  224. s := '';
  225. for n := 1 to x do
  226. s := s + ':0';
  227. s := s + ':';
  228. Result := replacestring(value, '::', s);
  229. end;
  230. {==============================================================================}
  231. function StrToIp6(Value: string): TIp6Bytes;
  232. var
  233. IPv6: TIp6Words;
  234. Index: Integer;
  235. n: integer;
  236. b1, b2: byte;
  237. s: string;
  238. x: integer;
  239. begin
  240. for n := 0 to 15 do
  241. Result[n] := 0;
  242. for n := 0 to 7 do
  243. Ipv6[n] := 0;
  244. Index := 0;
  245. Value := ExpandIP6(value);
  246. if value = '' then
  247. exit;
  248. while Value <> '' do
  249. begin
  250. if Index > 7 then
  251. Exit;
  252. s := fetch(value, ':');
  253. if s = '@' then
  254. break;
  255. if s = '' then
  256. begin
  257. IPv6[Index] := 0;
  258. end
  259. else
  260. begin
  261. x := StrToIntDef('$' + s, -1);
  262. if (x > 65535) or (x < 0) then
  263. Exit;
  264. IPv6[Index] := x;
  265. end;
  266. Inc(Index);
  267. end;
  268. for n := 0 to 7 do
  269. begin
  270. b1 := ipv6[n] div 256;
  271. b2 := ipv6[n] mod 256;
  272. Result[n * 2] := b1;
  273. Result[(n * 2) + 1] := b2;
  274. end;
  275. end;
  276. {==============================================================================}
  277. //based on routine by the Free Pascal development team
  278. function Ip6ToStr(value: TIp6Bytes): string;
  279. var
  280. i, x: byte;
  281. zr1,zr2: set of byte;
  282. zc1,zc2: byte;
  283. have_skipped: boolean;
  284. ip6w: TIp6words;
  285. begin
  286. zr1 := [];
  287. zr2 := [];
  288. zc1 := 0;
  289. zc2 := 0;
  290. for i := 0 to 7 do
  291. begin
  292. x := i * 2;
  293. ip6w[i] := value[x] * 256 + value[x + 1];
  294. if ip6w[i] = 0 then
  295. begin
  296. include(zr2, i);
  297. inc(zc2);
  298. end
  299. else
  300. begin
  301. if zc1 < zc2 then
  302. begin
  303. zc1 := zc2;
  304. zr1 := zr2;
  305. zc2 := 0;
  306. zr2 := [];
  307. end;
  308. end;
  309. end;
  310. if zc1 < zc2 then
  311. begin
  312. zr1 := zr2;
  313. end;
  314. SetLength(Result, 8*5-1);
  315. SetLength(Result, 0);
  316. have_skipped := false;
  317. for i := 0 to 7 do
  318. begin
  319. if not(i in zr1) then
  320. begin
  321. if have_skipped then
  322. begin
  323. if Result = '' then
  324. Result := '::'
  325. else
  326. Result := Result + ':';
  327. have_skipped := false;
  328. end;
  329. Result := Result + IntToHex(Ip6w[i], 1) + ':';
  330. end
  331. else
  332. begin
  333. have_skipped := true;
  334. end;
  335. end;
  336. if have_skipped then
  337. if Result = '' then
  338. Result := '::0'
  339. else
  340. Result := Result + ':';
  341. if Result = '' then
  342. Result := '::0';
  343. if not (7 in zr1) then
  344. SetLength(Result, Length(Result)-1);
  345. Result := LowerCase(result);
  346. end;
  347. {==============================================================================}
  348. function ReverseIP(Value: AnsiString): AnsiString;
  349. var
  350. x: Integer;
  351. begin
  352. Result := '';
  353. repeat
  354. x := LastDelimiter('.', Value);
  355. Result := Result + '.' + Copy(Value, x + 1, Length(Value) - x);
  356. Delete(Value, x, Length(Value) - x + 1);
  357. until x < 1;
  358. if Length(Result) > 0 then
  359. if Result[1] = '.' then
  360. Delete(Result, 1, 1);
  361. end;
  362. {==============================================================================}
  363. function ReverseIP6(Value: AnsiString): AnsiString;
  364. var
  365. ip6: TIp6bytes;
  366. n: integer;
  367. x, y: integer;
  368. begin
  369. ip6 := StrToIP6(Value);
  370. x := ip6[15] div 16;
  371. y := ip6[15] mod 16;
  372. Result := IntToHex(y, 1) + '.' + IntToHex(x, 1);
  373. for n := 14 downto 0 do
  374. begin
  375. x := ip6[n] div 16;
  376. y := ip6[n] mod 16;
  377. Result := Result + '.' + IntToHex(y, 1) + '.' + IntToHex(x, 1);
  378. end;
  379. end;
  380. {==============================================================================}
  381. end.