r3wp [groups: 83 posts: 189283]
  • Home
  • Script library
  • AltME Archive
  • Mailing list
  • Articles Index
  • Site search
 

World: r3wp

[Core] Discuss core issues

Pekr
16-Apr-2010
[16325x3]
Did anyone do IP arithmetics? I need to check, if some ip is in correct 
range  :-)


I have e.g. IP 10.10.10.10, and I need to check, if it belongs to 
10.10.0.0/16. I have very primitive (but probably complicated function, 
which can't however count with cases where mask is different from 
8. 16, 24, or 32:

in-ip-range?: func [ip-fw ip-sq /local is? ip-sq-tmp ip-fw-tmp][


  ;--- turn ip-string into block of separated values- removes dots 
  and slash ["10" "10" "10" "10" "24"]
  ip-sq-tmp: parse ip-sq "./"
  ip-fw-tmp: parse ip-fw "."

  mask:  last ip-sq-tmp
  ip-sq: copy/part ip-sq-tmp 4
  ip-fw: copy/part ip-fw-tmp 4
   
  switch/default mask [

    "8"  [either (copy/part ip-fw 1) = (copy/part ip-sq 1) [is?: true][is?: 
    false]]

    "16" [either (copy/part ip-fw 2) = (copy/part ip-sq 2) [is?: true][is?: 
    false]]

    "24" [either (copy/part ip-fw 3) = (copy/part ip-sq 3) [is?: true][is?: 
    false]]

    "32" [either (copy/part ip-fw 4) = (copy/part ip-sq 4) [is?: true][is?: 
    false]]
  ][
     is?: false

     print ["Mas not found: " mask ", the result will most probably contain 
     false positives ..."]
  ]

 return is?

]
calling convetions: is-in-range? "10.10.10.10" "10.10.10.0/24"
ah, should be in-ip-range? in line above ...
BrianH
16-Apr-2010
[16328x5]
Convert to integers (through tuple then binary) and do bitwise operations.
>> ip: to-tuple "10.10.10.10"
== 10.10.10.10
>> ip-as-integer: to-integer to-binary to-tuple "10.10.10.10"
== 168430090
>> set [mask-ip mask-range] parse "10.10.10.0/24" "/"
== ["10.10.10.0" "24"]
>> mask-ip: to-tuple mask-ip
== 10.10.10.0
>> mask-range: to-integer mask-range
== 24

>> mask-integer: (to-integer to-binary mask-ip) and (-1 xor (to-integer 
2 ** (32 - mask-range)) - 1)
== 168430080
>> mask-integer = (ip-as-integer and mask-integer)
== true
That process can be converted to the algorithm for your function:

in-ip-range?: funct [ip-fw ip-sq] [
    ; Convert ip to integer
    ip-as-integer: to-integer to-binary to-tuple ip-fw
    ; Convert mask to tuple and range integer
    set [mask-ip mask-range] parse ip-sq "/"
    mask-ip: to-tuple mask-ip
    mask-range: to-integer mask-range
    ; Calculate mask as integer

    mask-integer: (to-integer to-binary mask-ip) and (-1 xor (to-integer 
    2 ** (32 - mask-range)) - 1)
    ; Is ip within mask?
    mask-integer = (ip-as-integer and mask-integer)
]
Passes testing here, R2 and R3.
Of course FUNCT was added in 2.7.7, so if you use earlier versions 
use FUNC and collect your own locals.
And this version can handle all mask ranges, not just 8, 16, 24 and 
32.
Steeve
16-Apr-2010
[16333x3]
>> (-1 xor (to-integer 2 ** (32 - mask-range)) - 1)
same thing than:
>>shift  -1 mask-range
sorry, I mean
shift  -1 32 - mask-range
not tested though...
Andreas
16-Apr-2010
[16336]
Only in R3, though, where, per default, shift == lshift, in R2 shift 
== rshift.
Steeve
16-Apr-2010
[16337]
ah yes, I forgot
Andreas
16-Apr-2010
[16338x4]
R2 needs shift/left to lshift, R3 rshifts with negative offsets.
And Brian, I fear your function is flawed.
>> in-ip-range? "10.10.10.10" "10.10.0.0/24" ; == true
Which is wrong.
From a quick glance your masking logic is wrong. You need to mask 
both the address and the network and then compare if the results 
match.
Steeve
16-Apr-2010
[16342]
I guess it's in the last line::::
ip-as-integer = (ip-as-integer and mask-integer)
Andreas
16-Apr-2010
[16343x3]
I have a correct function for R3 lying around somewhere ... if only 
I could find it :)
Ah, got it.
cidr-match?: funct [address [tuple!] network [tuple!] bits [integer!]] 
[
    mask: skip to-binary (shift -1 32 - bits) 4
    (mask and to-binary address) = (mask and to-binary network)
]
Steeve
16-Apr-2010
[16346]
not R2 though ;-)
Andreas
16-Apr-2010
[16347]
For R3
, as I mentioned.
Steeve
16-Apr-2010
[16348]
I on
Andreas
16-Apr-2010
[16349x3]
Usage:
>> cidr-match? 10.10.10.10 10.10.0.0 16 ; == true
>> cidr-match? 10.10.10.10 10.10.0.0 24 ; == false
It's much nicer in R3, as to-binary on numbers works properly :)
In any case, here's an R2 version (assuming 2.7.7+ for funct):


cidr-match?: funct [address [tuple!] network [tuple!] bits [integer!]] 
[
    mask: shift/left -1 32 - bits

    (mask and to-integer to-binary address) = (mask and to-integer to-binary 
    network)
]
Steeve
16-Apr-2010
[16352]
See that weird one :)


cidr-match?: funct [address [tuple!] network [tuple!] bits [integer!]] 
[
    mask: to-tuple skip to-binary (shift -1 32 - bits) 4
    mask and address xor network = .0.
]
BrianH
16-Apr-2010
[16353]
Andreas, I'm sure my function is flawed - I just came up with it 
right then. Thanks for the fix :)
Steeve
16-Apr-2010
[16354]
rather optimized...


cidr-match?: funct [address [tuple!] network [tuple!] bits [integer!]] 
[
    mask: to-tuple to-binary shift -1 64 - bits
    mask and address xor network = .0.
]
Andreas
16-Apr-2010
[16355]
Heh, that's great Steeve. Esp the ".0."
Steeve
16-Apr-2010
[16356]
yeah,
.0. = 0.0.0 = 0.0.0.0.0 ...
Andreas
16-Apr-2010
[16357]
Yeah :)
BrianH
16-Apr-2010
[16358x2]
Yeah, silly me, forgot about SHIFT :)
That should work on R2 with 32 instead of 64.
Steeve
16-Apr-2010
[16360]
Yup
Andreas
16-Apr-2010
[16361]
Nope. You'd need shift/left on R2
Steeve
16-Apr-2010
[16362]
He knew... :)
Andreas
16-Apr-2010
[16363]
Just a reminder :)
BrianH
16-Apr-2010
[16364x2]
The last time I did IP calculations in REBOL was before 2.7.6 came 
out, so the reminder is appreciated :)
Though your functions do indicate the value of using REBOL's datatypes 
properly. Take note, Pekr, no strings :)
Pekr
17-Apr-2010
[16366x2]
wow, what a bunch of reactions :-) BrianH - I used strings, because 
of original Mikrotik format. They use 10.10.10.10/24 format for IP, 
so it was easier for me to carry around in a string form, then parse 
it later when needed ....


IP arithmetics, and ranges would be 2 nice new datatypes for REBOL 
imo :-)
Steeve - your optimised version for R2 does not work correctly:

>> cidr-match? 10.10.10.10 10.10.10.0 24
== false
Steeve
17-Apr-2010
[16368]
Because it was for R3 only, try this for R2:


cidr-match?: func [address [tuple!] network [tuple!] bits [integer!]] 
[

    address xor network and (to-tuple debase/base to-hex shift/left -1 
    32 - bits 16) = .0.
]

Don't know if it's faster than Andreas's, though
ChristianE
17-Apr-2010
[16369]
(-:-:- = -:0:-) = (0:-:0 = 0:0:0)
Steeve
17-Apr-2010
[16370x2]
-:-
and so:
+:+
Henrik
18-Apr-2010
[16372]
I'm trying to figure out which index comes earlier in two different 
references to the same block and was trying with MIN and MAX, because 
I didn't want to resort to LESSER? INDEX? things.


The result with MIN/MAX doesn't seem to be particularly useful. What 
is the basis of comparison of two blocks when using MIN and MAX?
BrianH
18-Apr-2010
[16373]
Their contents, not their indexes.
Henrik
18-Apr-2010
[16374]
yes, I figure that, but what's the basis for comparison?