-1

I have a script where I am comparing the actual routing table from "netstat -rn" with the routing table configured in a security vendors own configuration. The problem is that while netstat -rn gives the netmask in format of "255.255.255.0" the command for displaying the routing table within the vendor gives it in the form of /24

I need to find a way to create a function, using only awk, to convert from subnet mask, example 255.255.255.0, to prefix, example: /24

function subnetmaskToPrefix(subnetmask) {
doing magic
}

subnetmask="255.255.255.0"
prefix=subnetmaskToPrefix(subnetmask)
Johnathan
  • 737
  • 2
  • 7
  • 21
  • [edit] your question to include concise, testable sample input and expected output and explain what you know about the required conversion algorithm. – Ed Morton Nov 25 '16 at 16:11
  • This link might be useful: http://stackoverflow.com/questions/10278513/bash-shell-decimal-to-binary-conversion – Michael Vehrs Nov 25 '16 at 16:40

4 Answers4

2

If the prefix number comes from the number of 1's in the subnet mask when converted to binary. example:

mask 255.255.255.0 is 11111111.11111111.11111111.00000000 in binary. This is 24 1's.

echo "255.255.255.0" | awk '
function count1s(N){
    c = 0
    for(i=0; i<8; ++i) if(and(2**i, N)) ++c
    return c
}
function subnetmaskToPrefix(subnetmask) {
    split(subnetmask, v, ".")
    return count1s(v[1]) + count1s(v[2]) + count1s(v[3]) + count1s(v[4])
}
{
    print("/" subnetmaskToPrefix($1))
}'

you get,

/24
Jose Ricardo Bustos M.
  • 8,016
  • 6
  • 40
  • 62
  • Makes sense, and I think I understand most of the two functions you have written, except for this part: if(and(2**i, N)) what does and(2**i, N) do? – Johnathan Nov 26 '16 at 06:52
  • I could mention that the awk flavor I use is not gawk, I think its awk or even hawk. – Johnathan Nov 26 '16 at 06:58
1

The below solution works great for gawk. But if you don't use gawk then you could use this function to count instead.

function count1s(N) {
    r=""                    # initialize result to empty (not 0)
    while(N!=0){            # as long as number still has a value
        r=((N%2)?"1":"0") r   # prepend the modulos2 to the result
        N=int(N/2)            # shift right (integer division by 2)
    }

    # count number of 1s
    r=gsub(/1/,"",r)
    # Return result
    return r

}
Johnathan
  • 737
  • 2
  • 7
  • 21
0

[Improvement points]

  1. You can save memory (and the operational cost of function calls) by reducing the number of function definitions.
  2. The mask binary cannot take like "11101". Therefore, the subloop (= pre-function of the original code) can be interrupted.

[code]

    awk 'function mask2cidr(mask){
      c=0; split(mask,v,".");
      for(j=1; j<5; j++){for(i=7; i>=0; i--){
        if(and(2**i,v[j])){c++;}else{return c;}
      }}
      return c;
    }
    { print("/" mask2cidr($1)) }';
hfft
  • 1
0

since all the 1's in a subnet mask are grouped together at the high side, there's absolutely no need to pre-make any of the binary-bit-strings, since "counting leading edge 1's"` is same as

1.      2^32 (or simply : ( 4 ^ 4 ) ^ 4 ) 
   minus
        integer of subnet mask bits

2. take the log-base-2 value of step-1, which gives you 
   # of 0-bits at the bottom 

   (a tiny 2^-16 has been padded for error-correction), and

3. finally, return `32 minus value of step-2`

tested and confirmed working on mawk, gawk, and nawk

mawk ' 
function _____(__,_,___,____) {
    return \
    substr(___="[.]" (_=""), __~("["(+_)".]"(+_)) \
    ? sub("^"(+_)"+",_,__) + gsub(___ (+_)"+",".",__):_,_) \
    "subnet-mask::/" (int(\
    log(-(__=____[_ =__ = split(__,____,___)] \
      + (___=_^=_+!--__) * ____[__]       \
      + (___  ^=   --__)  * ____[__]       \
      +  ____[_^!_]*_*___) + ___^(_+=_^=_<_)\
     ) / -log(_) - _^-_^_^_) \
                           + _^_^_*_)
}
BEGIN {  CONVFMT = "%.250g"
    _+= _^= OFMT = "%.25g"
}
($++NF = _____($_))^!_'
  1. 1st column is reference answer
  2. 2nd column the IPv4-equivalent of that subnet mask, and
  3. 3rd column the calculated one via the function
/0 000.000.000.000 subnet-mask::/0  # this line only included for completeness

/1 128.000.000.000 subnet-mask::/1
/2 192.000.000.000 subnet-mask::/2
/3 224.000.000.000 subnet-mask::/3
/4 240.000.000.000 subnet-mask::/4
/5 248.000.000.000 subnet-mask::/5
/6 252.000.000.000 subnet-mask::/6
/7 254.000.000.000 subnet-mask::/7
/8 255.000.000.000 subnet-mask::/8

/9 255.128.000.000 subnet-mask::/9
/10 255.192.000.000 subnet-mask::/10
/11 255.224.000.000 subnet-mask::/11
/12 255.240.000.000 subnet-mask::/12
/13 255.248.000.000 subnet-mask::/13
/14 255.252.000.000 subnet-mask::/14
/15 255.254.000.000 subnet-mask::/15
/16 255.255.000.000 subnet-mask::/16

/17 255.255.128.000 subnet-mask::/17
/18 255.255.192.000 subnet-mask::/18
/19 255.255.224.000 subnet-mask::/19
/20 255.255.240.000 subnet-mask::/20
/21 255.255.248.000 subnet-mask::/21
/22 255.255.252.000 subnet-mask::/22
/23 255.255.254.000 subnet-mask::/23
/24 255.255.255.000 subnet-mask::/24

/25 255.255.255.128 subnet-mask::/25
/26 255.255.255.192 subnet-mask::/26
/27 255.255.255.224 subnet-mask::/27
/28 255.255.255.240 subnet-mask::/28
/29 255.255.255.248 subnet-mask::/29
/30 255.255.255.252 subnet-mask::/30
/31 255.255.255.254 subnet-mask::/31
RARE Kpop Manifesto
  • 2,453
  • 3
  • 11