X-Git-Url: http://www.lcore.org/git/lcore.git/blobdiff_plain/6cb6b7ede2d178e03fa817bc28474c175f5a93b9..71f094bad8c68b2a3d096b436dc74cf4d9e2895a:/binipstuff.pas?ds=sidebyside diff --git a/binipstuff.pas b/binipstuff.pas old mode 100755 new mode 100644 index 0c23533..1d7a7c2 --- a/binipstuff.pas +++ b/binipstuff.pas @@ -4,37 +4,42 @@ ----------------------------------------------------------------------------- } unit binipstuff; +{$ifdef fpc} +{$mode delphi} +{$endif} + interface {$include lcoreconfig.inc} -{$ifndef win32} -{$ifdef ipv6} -uses sockets; -{$endif} +uses +{$ifndef mswindows} + sockets, {$endif} + pgtypes; -{$ifdef fpc} - {$mode delphi} -{$endif} -{$ifdef cpu386}{$define i386}{$endif} -{$ifdef i386}{$define ENDIAN_LITTLE}{$endif} + +{$include pgtypes.inc} {$include uint32.inc} const - hexchars:array[0..15] of char='0123456789abcdef'; - AF_INET=2; - {$ifdef win32} + hexchars:array[0..15] of ansichar='0123456789abcdef'; + {$ifdef mswindows} + AF_INET=2; AF_INET6=23; {$else} - AF_INET6=10; + //redeclare these constants so units that use us can use them + //without using sockets directly + AF_INET=AF_INET; + AF_INET6=AF_INET6; + //AF_INET6=10; {$endif} type {$ifdef ipv6} - {$ifdef win32} + {$ifdef mswindows} {$define want_Tin6_addr} {$endif} {$ifdef ver1_0} @@ -65,55 +70,59 @@ type {$endif} end; - {$ifdef win32} - TInetSockAddr = packed Record - family:Word; - port :Word; - addr :uint32; - pad :array [1..8] of byte; - end; - {$ifdef ipv6} + {zipplet 20170204: FPC 3.0.0 changed the definition of TInetSockAddr: + - http://www.freepascal.org/docs-html/rtl/sockets/tinetsockaddr.html + - http://www.freepascal.org/docs-html/rtl/sockets/sockaddr_in.html + Due to this, TInetSockAddr -> TLInetSockAddr4 / TLInetSockAddr6 + Using our own types no matter what OS or compiler version will prevent future problems. + Adding "4" to non IPv6 record names improves code clarity } - TInetSockAddr6 = packed record - sin6_family: word; - sin6_port: word; - sin6_flowinfo: uint32; - sin6_addr: tin6_addr; - sin6_scope_id: uint32; - end; + {$ifndef mswindows} + //zipplet 20170204: Do we still need to support ver1_0? Perhaps a cleanup is in order. + //For now keep supporting it for compatibility. + {$ifdef ver1_0} + cuint16 = word; + cuint32 = dword; + sa_family_t = word; {$endif} {$endif} - - - {$ifdef ipv6} - {$ifdef ver1_0} - cuint16=word; - cuint32=dword; - sa_family_t=word; - - {$endif} + TLInetSockAddr4 = packed Record + family:Word; + port :Word; + addr :uint32; + pad :array [0..7] of byte; //zipplet 20170204 - originally this was 1..8 for some reason + end; + + {$ifdef ipv6} + TLInetSockAddr6 = packed record + sin6_family: word; + sin6_port: word; + sin6_flowinfo: uint32; + sin6_addr: tin6_addr; + sin6_scope_id: uint32; + end; {$endif} + + //zipplet 20170204: I did not rename the unioned record. We might want to rename this to TLinetSockAddrv TinetSockAddrv = packed record case integer of - 0: (InAddr:TInetSockAddr); + 0: (InAddr:TLInetSockAddr4); {$ifdef ipv6} - 1: (InAddr6:TInetSockAddr6); + 1: (InAddr6:TLInetSockAddr6); {$endif} end; Pinetsockaddrv = ^Tinetsockaddrv; type - tsockaddrin=TInetSockAddr; - - + tsockaddrin=TLInetSockAddr4; { bin IP list code, by beware while this is really just a string, on the interface side it must be treated as an opaque var which is passed as "var" when it needs to be modified} - tbiniplist=string; + tbiniplist=tbufferstring; function biniplist_new:tbiniplist; procedure biniplist_add(var l:tbiniplist;ip:tbinip); @@ -123,32 +132,41 @@ procedure biniplist_set(var l:tbiniplist;index:integer;ip:tbinip); procedure biniplist_setcount(var l:tbiniplist;newlen:integer); procedure biniplist_free(var l:tbiniplist); procedure biniplist_addlist(var l:tbiniplist;const l2:tbiniplist); -function biniplist_tostr(const l:tbiniplist):string; +function biniplist_tostr(const l:tbiniplist):thostname; +function isbiniplist(const l:tbiniplist):boolean; function htons(w:word):word; function htonl(i:uint32):uint32; -function ipstrtobin(const s:string;var binip:tbinip):boolean; -function ipstrtobinf(const s:string):tbinip; -function ipbintostr(const binip:tbinip):string; +function ipstrtobin(const s:thostname;var binip:tbinip):boolean; +function ipstrtobinf(const s:thostname):tbinip; +function ipbintostr(const binip:tbinip):thostname; {$ifdef ipv6} -function ip6bintostr(const bin:tin6_addr):string; -function ip6strtobin(const s:string;var bin:tin6_addr):boolean; +function ip6bintostr(const bin:tin6_addr):thostname; +function ip6strtobin(const s:thostname;var bin:tin6_addr):boolean; {$endif} function comparebinip(const ip1,ip2:tbinip):boolean; procedure maskbits(var binip:tbinip;bits:integer); function comparebinipmask(ip1,ip2:tbinip;bits:integer):boolean; +procedure addipsoffamily(var l:tbiniplist;const l2:tbiniplist;family:integer); + {deprecated} -function longip(s:string):longint; +function longip(s:thostname):longint; +function needconverttov4(const ip:tbinip):boolean; procedure converttov4(var ip:tbinip); +procedure converttov6(var ip:tbinip); function inaddrvtobinip(inaddrv:tinetsockaddrv):tbinip; -function makeinaddrv(addr:tbinip;port:string;var inaddr:tinetsockaddrv):integer; +function makeinaddrv(addr:tbinip;port:ansistring;var inaddr:tinetsockaddrv):integer; function inaddrsize(inaddr:tinetsockaddrv):integer; +function getbinipbitlength(const ip:tbinip):integer; +function getipstrbitlength(const ip:thostname):integer; +function getfamilybitlength(family:integer):integer; + implementation uses sysutils; @@ -181,7 +199,7 @@ begin {$endif} end; -function makeinaddrv(addr:tbinip;port:string;var inaddr:tinetsockaddrv):integer; +function makeinaddrv(addr:tbinip;port:ansistring;var inaddr:tinetsockaddrv):integer; begin result := 0; { biniptemp := forwardlookup(addr,10);} @@ -191,14 +209,14 @@ begin inAddr.InAddr.family:=AF_INET; inAddr.InAddr.port:=htons(strtointdef(port,0)); inAddr.InAddr.addr:=addr.ip; - result := sizeof(tinetsockaddr); + result := sizeof(tlinetsockaddr4); end else {$ifdef ipv6} if addr.family = AF_INET6 then begin inAddr.InAddr6.sin6_family:=AF_INET6; inAddr.InAddr6.sin6_port:=htons(strtointdef(port,0)); inAddr.InAddr6.sin6_addr:=addr.ip6; - result := sizeof(tinetsockaddr6); + result := sizeof(tlinetsockaddr6); end; {$endif} end; @@ -206,18 +224,18 @@ end; function inaddrsize(inaddr:tinetsockaddrv):integer; begin {$ifdef ipv6} - if inaddr.inaddr.family = AF_INET6 then result := sizeof(tinetsockaddr6) else + if inaddr.inaddr.family = AF_INET6 then result := sizeof(tlinetsockaddr6) else {$endif} - result := sizeof(tinetsockaddr); + result := sizeof(tlinetsockaddr4); end; {internal} {converts dotted v4 IP to longint. returns host endian order} -function longip(s:string):longint; +function longip(s:thostname):longint; var l:longint; a,b:integer; -function convertbyte(const s:string):integer; +function convertbyte(const s:ansistring):integer; begin result := strtointdef(s,-1); if result < 0 then begin @@ -268,7 +286,7 @@ begin ipstrtobin(s,result); end; -function ipstrtobin(const s:string;var binip:tbinip):boolean; +function ipstrtobin(const s:thostname;var binip:tbinip):boolean; begin binip.family := 0; result := false; @@ -282,7 +300,10 @@ begin {$endif} {try v4} - binip.ip := htonl(longip(s)); + // zipplet: htonl() expects a uint32 but longip() spits out longint. + // Because longip() is deprecated, we do not fix it but typecast. + //binip.ip := htonl(longip(s)); + binip.ip := htonl(uint32(longip(s))); if (binip.ip <> 0) or (s = '0.0.0.0') then begin result := true; binip.family := AF_INET; @@ -290,7 +311,7 @@ begin end; end; -function ipbintostr(const binip:tbinip):string; +function ipbintostr(const binip:tbinip):thostname; var a:integer; begin @@ -313,11 +334,11 @@ end; { IPv6 address binary to/from string conversion routines -written by beware (steendijk at xs4all dot nl) +written by beware - implementation does not depend on other ipv6 code such as the tin6_addr type, the parameter can also be untyped. -- it is host endian neutral - binary format is aways network order +- it is host endian neutral - binary format is always network order - it supports compression of zeroes - it supports ::ffff:192.168.12.34 style addresses - they are made to do the Right Thing, more efficient implementations are possible @@ -326,9 +347,9 @@ written by beware (steendijk at xs4all dot nl) {fpc has hostaddrtostr6 and strtohostaddr6 but the later isnt implemented yet} -function ip6bintostr(const bin:tin6_addr):string; +function ip6bintostr(const bin:tin6_addr):thostname; {base16 with lowercase output} -function makehex(w:word):string; +function makehex(w:word):ansistring; begin result := ''; if w >= 4096 then result := result + hexchars[w shr 12]; @@ -368,6 +389,13 @@ begin end; end; end; + + {run length at least 2 0 words} + if (runlength = 1) then begin + runlength := 0; + runbegin := 0; + end; + result := ''; for a := 0 to runbegin-1 do begin if (a <> 0) then result := result + ':'; @@ -384,10 +412,10 @@ begin end; end; -function ip6strtobin(const s:string;var bin:tin6_addr):boolean; +function ip6strtobin(const s:thostname;var bin:tin6_addr):boolean; var a,b:integer; - fields:array[0..7] of string; + fields:array[0..7] of ansistring; fieldcount:integer; emptyfield:integer; wordcount:integer; @@ -498,25 +526,62 @@ begin result := comparebinip(ip1,ip2); end; -{converts a binary IP to v4 if it is a v6 IP in the v4 range} -procedure converttov4(var ip:tbinip); +function needconverttov4(const ip:tbinip):boolean; begin {$ifdef ipv6} if ip.family = AF_INET6 then begin if (ip.ip6.u6_addr32[0] = 0) and (ip.ip6.u6_addr32[1] = 0) and (ip.ip6.u6_addr16[4] = 0) and (ip.ip6.u6_addr16[5] = $ffff) then begin - ip.family := AF_INET; - ip.ip := ip.ip6.s6_addr32[3]; + result := true; + exit; end; end; {$endif} + + result := false; end; -{------------------------------------------------------------------------------} +{converts a binary IP to v4 if it is a v6 IP in the v4 range} +procedure converttov4(var ip:tbinip); +begin + {$ifdef ipv6} + if needconverttov4(ip) then begin + ip.family := AF_INET; + ip.ip := ip.ip6.s6_addr32[3]; + end; + {$endif} +end; + + +{converts a binary IP to v6 if it is a v4 IP} +procedure converttov6(var ip:tbinip); +begin + {$ifdef ipv6} + if ip.family = AF_INET then begin + ip.family := AF_INET6; + ip.ip6.s6_addr32[3] := ip.ip; + ip.ip6.u6_addr32[0] := 0; + ip.ip6.u6_addr32[1] := 0; + ip.ip6.u6_addr16[4] := 0; + ip.ip6.u6_addr16[5] := $ffff; + end; + {$endif} +end; + + +{-----------biniplist stuff--------------------------------------------------} +const + biniplist_prefix: ansistring = 'bipl'#0; + //fpc 1.0.x doesn't seem to like use of length function in a constant + //definition + //biniplist_prefixlen=length(biniplist_prefix); + + biniplist_prefixlen=5; + function biniplist_new:tbiniplist; begin - result := ''; + result := biniplist_prefix; end; procedure biniplist_add(var l:tbiniplist;ip:tbinip); @@ -530,7 +595,7 @@ end; function biniplist_getcount(const l:tbiniplist):integer; begin - result := length(l) div sizeof(tbinip); + result := (length(l)-biniplist_prefixlen) div sizeof(tbinip); end; function biniplist_get(const l:tbiniplist;index:integer):tbinip; @@ -539,18 +604,18 @@ begin fillchar(result,sizeof(result),0); exit; end; - move(l[index*sizeof(tbinip)+1],result,sizeof(result)); + move(l[index*sizeof(tbinip)+1+biniplist_prefixlen],result,sizeof(result)); end; procedure biniplist_set(var l:tbiniplist;index:integer;ip:tbinip); begin uniquestring(l); - move(ip,l[index*sizeof(tbinip)+1],sizeof(ip)); + move(ip,l[index*sizeof(tbinip)+1+biniplist_prefixlen],sizeof(ip)); end; procedure biniplist_setcount(var l:tbiniplist;newlen:integer); begin - setlength(l,sizeof(tbinip)*newlen); + setlength(l,(sizeof(tbinip)*newlen)+biniplist_prefixlen); end; procedure biniplist_free(var l:tbiniplist); @@ -560,10 +625,10 @@ end; procedure biniplist_addlist; begin - l := l + l2; + l := l + copy(l2,biniplist_prefixlen+1,maxlongint); end; -function biniplist_tostr(const l:tbiniplist):string; +function biniplist_tostr(const l:tbiniplist):thostname; var a:integer; begin @@ -575,4 +640,50 @@ begin result := result + ')'; end; +function isbiniplist(const l:tbiniplist):boolean; +var + i : integer; +begin + for i := 1 to biniplist_prefixlen do begin + if biniplist_prefix[i] <> l[i] then begin + result := false; + exit; + end; + end; + result := true; +end; + +procedure addipsoffamily(var l:tbiniplist;const l2:tbiniplist;family:integer); +var + a:integer; + biniptemp:tbinip; +begin + for a := biniplist_getcount(l2)-1 downto 0 do begin + biniptemp := biniplist_get(l2,a); + if (biniptemp.family = family) then biniplist_add(l,biniptemp); + end; +end; + +function getfamilybitlength(family:integer):integer; +begin + {$ifdef ipv6} + if family = AF_INET6 then result := 128 else + {$endif} + if family = AF_INET then result := 32 + else result := 0; +end; + +function getbinipbitlength(const ip:tbinip):integer; +begin + result := getfamilybitlength(ip.family); +end; + +function getipstrbitlength(const ip:thostname):integer; +var + biniptemp:tbinip; +begin + ipstrtobin(ip,biniptemp); + result := getbinipbitlength(biniptemp); +end; + end.