Convert one byte data to hex

I need some ideas to convert a static route from RouterOS to hex.

Example: A route to the network 192.168.2.0/24 using gateway 192.168.1.1

The string to convert: [Network Bitmask][Network Address][IP Address]

Final hex string: 0x18c0a802c0a80101

My first suggestion - it should be 0x18c0a802**00**c0a80101. What if the mask if more specific than /24? :wink:

  1. I’m just learning to write scripts - and I think that was quite easy :slight_smile:.
  2. That’s my first script to be put on MikroTik wiki
  3. THG - if you are planning to go to the MUM - you owe me a beer :slight_smile: (wait… they give beer for free… ok, let it be a big chocolate :stuck_out_tongue:)
#
# Script converting network and gateway from routing table to hexadecimal string
# dst-address=192.168.2.0/24 gateway=192.168.1.1 => result=0x18c0a80200c0a80101
#
# (c) Daniel Starnowski 2011
#
:foreach route in=[/ip route find] do={
 :local dst [/ip route get $route dst-address];
 :local gateway [/ip route get $route gateway];
 :if ($gateway=[:toip $gateway]) do={
  :local total ($dst . "." . $gateway);
  :local result "0x";
  :local hextable [:toarray "0,1,2,3,4,5,6,7,8,9,a,b,c,d,e,f"];
  :local total2 "";
  :local decimal;
  :local division;
  :local i;
  :local j;
  :for i from=1 to=[:len $total] step=1 do={
   :set j [:pick $total ($i-1) $i];
   :if (($j=".") or ($j="/")) do={:set j ","};
   :set total2 ($total2 . $j);
   };
  :set total2 [:toarray $total2];

  :for i from=0 to=8 step=1 do={
   :set j $i;
   :if ($j<5) do={if ($j=0) do={:set j 4;} else={:set j ($j-1);};};
   :set decimal [:pick $total2 $j ($j+1)]
   :set division ($decimal / 16);
   :set result ($result . [:pick $hextable $division]);
   :set result ($result . [:pick $hextable ($decimal - (16 * $division))]);
   };
  :put $result;
 } else={:put ("Gateway is not a single IP address for ".$dst);}
}

This will generate an error on the dhcp client (the data is invalid).

If I set the network bits to “/25”, then the CIDR bit usage changes.


The string would be:

24 bits = 18c0a802c0a80101
25 bits = 19c0a80200c0a80101
192.168.2.0-24.png
192.168.2.0-25.png

Then how should it look like for:
192.168.0.0/16
10.0.0.0/8
10.0.0.0/16
10.0.0.0/20
10.0.0.0/24
10.0.0.0/28
? :slight_smile:

Thank you!

I’m trying to learn to write scripts in RouterOS, I must say that it’s quite easier to write scripts in a Unix machine.

You like chocolate, I’ll remeber that if I attend to the next MUM in Warsaw.

If the gateway address is the same (192.168.1.1).

192.168.0.0/16 = 0x10c0a8c0a80101
10.0.0.0/8 = 0x080ac0a80101
10.0.0.0/16 = 0x100a00c0a80101
10.0.0.0/20 = 0x140a0000c0a80101
10.0.0.0/24 = 0x180a0000c0a80101
10.0.0.0/28 = 0x1c0a000000c0a80101


If you have a computer with perl or ruby, try these scripts.

http://forum.mikrotik.com/t/calculate-dhcp-option-121-classless-static-route-option/43789/1

In your script above, did you forget to add a closing bracket to the end of it?

Ok, this modification was quick :slight_smile:.
And the perl script you gave me as example - gives invalid result for /0 mask. In that RFC (see the examples in the RFC) - should be no octets, but the perl script gives one :wink:.

#
# Second script converting network and gateway from routing table to hexadecimal string
# according to RFC 3442
# result=0x<prefix><network><gateway>
# example: dst-address=192.168.2.0/24 gateway=192.168.1.1 => result=0x18c0a802c0a80101
#
#        Width of subnet mask     Number of significant octets
#                     0                     0
#                  1- 8                     1
#                  9-16                     2
#                 17-24                     3
#                 25-32                     4
#
# (c) Daniel Starnowski 2011
#
:foreach route in=[/ip route find] do={
:local dst [/ip route get $route dst-address];
:local gateway [/ip route get $route gateway];
:if ($gateway=[:toip $gateway]) do={
  :local total ($dst . "." . $gateway);
  :local result "0x";
  :local hextable [:toarray "0,1,2,3,4,5,6,7,8,9,a,b,c,d,e,f"];
  :local total2 "";
  :local decimal;
  :local division;
  :local i;
  :local j;
  :for i from=1 to=[:len $total] step=1 do={
   :set j [:pick $total ($i-1) $i];
   :if (($j=".") or ($j="/")) do={:set j ","};
   :set total2 ($total2 . $j);
   };
  :set total2 [:toarray $total2];

  :set decimal [:pick $total2 4]
  :set division ($decimal / 16);
  :set result ($result . [:pick $hextable $division]);
  :set result ($result . [:pick $hextable ($decimal - (16 * $division))]);
  :local omit ((32-[:pick $total2 4]) / 8);

  :for i from=($omit+1) to=8 step=1 do={
   :set j $i;
   :if ($j<5) do={:set j ($j-1-$omit);};
   :set decimal [:pick $total2 $j]
   :set division ($decimal / 16);
   :set result ($result . [:pick $hextable $division]);
   :set result ($result . [:pick $hextable ($decimal - (16 * $division))]);
   };
  :put ($result . " for " . $dst);
} else={:put ("Gateway is not a single IP address for ".$dst);}
}

Can you give me an example, thanks.

dasiu@admin:~/Dokumenty/Mikrotik/Skrypty$ ./dhcp.perl 16.32.64.128 0.0.0.0/0

DHCP option 121 (249) hex string: 000010204080
  • should be 0010204080, and is 00**00**10204080. RFC says, that for subnet mask /0 - there should be 0 octets of the network, and the perl script still gives 1 octet in the result :slight_smile:.

From the RFC 3442 - see the first example:

       Width of subnet mask     Number of significant octets
                     0                     0
                  1- 8                     1
                  9-16                     2
                 17-24                     3
                 25-32                     4

   The following table contains some examples of how various subnet
   number/mask combinations can be encoded:

   Subnet number   Subnet mask      Destination descriptor
   0               0                0
   10.0.0.0        255.0.0.0        8.10
   10.0.0.0        255.255.255.0    24.10.0.0
   10.17.0.0       255.255.0.0      16.10.17
   10.27.129.0     255.255.255.0    24.10.27.129
   10.229.0.128    255.255.255.128  25.10.229.0.128
   10.198.122.47   255.255.255.255  32.10.198.122.47

So then - line 16 of the perl script given by you:
$string .= sprintf(‘%02x’, $b0);
should be:
$string .= sprintf(‘%02x’, $b0) if($mask > 0);

You are right, I must have forgotten to add “if($mask > 0)” to the perl script (it’s corrected now).

Another karma granted for this one. :slight_smile: