Community discussions

MikroTik App
 
lvader
just joined
Topic Author
Posts: 11
Joined: Tue Mar 27, 2018 8:10 pm

newb in scripting: getting byte value from lease-options string.

Sun Dec 11, 2022 2:23 pm

Good day.
I'm relatively new to mikrotik scripting, so haven't found myself good answer and asking for pointers to right direction.

I'm trying to parse as part of dhcp-client lease script variable in lease-options array. Specifically the option 212 (6rd dhcp info).
It is present there as type string, length 22 bytes.
First byte is netmask length, e.g. \0E.
Second byte is 6rd prefix length, like \26
Then, in the end of the option, 4 bytes of ipv4 address of tunnel endpoint.

What I'm looking for, is hint on how to do things like getting byte \0E and convert it to numeric 14? Something like 'ord()' function?
Or get 4 bytes from string, and convert them to valid IPv4 address to use further in script.

Any examples of similar script problems?
 
User avatar
rextended
Forum Guru
Forum Guru
Posts: 11982
Joined: Tue Feb 25, 2014 12:49 pm
Location: Italy
Contact:

Re: newb in scripting: getting byte value from lease-options string.

Mon Dec 12, 2022 2:41 am

Real example of option 212 value?

on this example netmask length 14, 6rd prefix length 38 and IPv4 192.168.100.1
:global opt "0E26DEADBEEFDEADBEEFDEADBEEFDEADBEEFC0A86401"

:put [[:parse ":return 0x$[:pick $opt 0 2]"]]

:put [[:parse ":return 0x$[:pick $opt 2 4]"]]

:put (0.0.0.0 + [[:parse ":return 0x$[:pick $opt 36 44]"]])
 
lvader
just joined
Topic Author
Posts: 11
Joined: Tue Mar 27, 2018 8:10 pm

Re: newb in scripting: getting byte value from lease-options string.

Mon Dec 12, 2022 11:07 am

Well, unfortunately that is not that easy. DHCP option comes as raw byte array inside string type, not as hex string representation.
Format of option 212 is like this (values are a bit changed, but should be good enough to get the idea):
:local v212 "\0E\26\20\01\22\02\F0\00\00\00\00\00\00\00\00\00\00\00\44\2B\FF\FE"
First byte is v4 mask length, second byte v6 prefix length. Then 16 bytes of ipv6 prefix. Then 4 bytes of 6to4 6rd tunnel endpoint.

The best that I came up with is something below. Ugly, to my taste, but good enough starting point:
:global string2array do={
    :local ascii "\00\01\02\03\04\05\06\07\08\09\0A\0B\0C\0D\0E\0F\
                  \10\11\12\13\14\15\16\17\18\19\1A\1B\1C\1D\1E\1F\
                  \20\21\22\23\24\25\26\27\28\29\2A\2B\2C\2D\2E\2F\
                  \30\31\32\33\34\35\36\37\38\39\3A\3B\3C\3D\3E\3F\
                  \40\41\42\43\44\45\46\47\48\49\4A\4B\4C\4D\4E\4F\
                  \50\51\52\53\54\55\56\57\58\59\5A\5B\5C\5D\5E\5F\
                  \60\61\62\63\64\65\66\67\68\69\6A\6B\6C\6D\6E\6F\
                  \70\71\72\73\74\75\76\77\78\79\7A\7B\7C\7D\7E\7F\
                  \80\81\82\83\84\85\86\87\88\89\8A\8B\8C\8D\8E\8F\
                  \90\91\92\93\94\95\96\97\98\99\9A\9B\9C\9D\9E\9F\
                  \A0\A1\A2\A3\A4\A5\A6\A7\A8\A9\AA\AB\AC\AD\AE\AF\
                  \B0\B1\B2\B3\B4\B5\B6\B7\B8\B9\BA\BB\BC\BD\BE\BF\
                  \C0\C1\C2\C3\C4\C5\C6\C7\C8\C9\CA\CB\CC\CD\CE\CF\
                  \D0\D1\D2\D3\D4\D5\D6\D7\D8\D9\DA\DB\DC\DD\DE\DF\
                  \E0\E1\E2\E3\E4\E5\E6\E7\E8\E9\EA\EB\EC\ED\EE\EF\
                  \F0\F1\F2\F3\F4\F5\F6\F7\F8\F9\FA\FB\FC\FD\FE\FF"
    :local string $1
    :if (([:typeof $string] != "str") or ($string = "")) do={ :return ({}) }
    :local lenstr [:len $string]
    :local res ({})
    :for pos from=0 to=($lenstr - 1) do={
        :local ord ([:find $ascii [:pick $string $pos ($pos + 1)] -1])
        :set res ($res, $ord)
    }
    :return $res
}

:local v212 "\0E\26\20\01\22\02\F0\00\00\00\00\00\00\00\00\00\00\00\44\2B\FF\FE"
:put [$string2array $v212]
 
User avatar
rextended
Forum Guru
Forum Guru
Posts: 11982
Joined: Tue Feb 25, 2014 12:49 pm
Location: Italy
Contact:

Re: newb in scripting: getting byte value from lease-options string.

Mon Dec 12, 2022 12:27 pm

:global charsString ""
:for x from=0 to=15 step=1 do={ :for y from=0 to=15 step=1 do={
    :local tmpHex "$[:pick "0123456789ABCDEF" $x ($x+1)]$[:pick "0123456789ABCDEF" $y ($y+1)]"
    :set $charsString "$charsString$[[:parse "(\"\\$tmpHex\")"]]"
} }

:global chr2int do={
    :global charsString
    :if (($1="") or ([:len $1] > 1) or ([:typeof $1] = "nothing")) do={:return -1}; :return [:find $charsString $1 -1]
}

:global chr2hex do={
    :global chr2int
    :local number  [:tonum [$chr2int $1]]
    :local hexadec "0"
    :local remainder 0
    :if ($number > 0) do={:set hexadec ""}
    :while ( $number > 0 ) do={
          :set remainder ($number % 16)
          :set number (($number-$remainder) / 16)
          :set hexadec ([:pick "0123456789ABCDEF" $remainder].$hexadec)
    } 
    :if ([:len $hexadec] = 1) do={:set hexadec "0$hexadec"}
    :return "$hexadec"
}

:global str2hex do={
    :global chr2hex
    :local string $1
    :if (([:typeof $string] != "str") or ($string = "")) do={ :return "" }
    :local lenstr [:len $string]
    :local constr ""
    :for pos from=0 to=($lenstr - 1) do={
        :set constr "$constr$[$chr2hex [:pick $string $pos ($pos + 1)]]"
    }
    :return $constr
}

:global str2intarr do={
    :global chr2int
    :local string $1
    :if (([:typeof $string] != "str") or ($string = "")) do={ :return "" }
    :local lenstr [:len $string]
    :local constr [:toarray ""]
    :for pos from=0 to=($lenstr - 1) do={
        :set ($constr->$pos) [$chr2int [:pick $string $pos ($pos + 1)]]
    }
    :return $constr
}

:global ipv6raw2format do={
    :local string $1
    :if (([:typeof $string] != "str") or ($string = "")) do={ :return "::" }
    :local lenstr [:len $string]
    :local constr ""
    :for pos from=0 to=($lenstr - 1) do={
        :if ((($pos % 4) = 0) and ($pos > 0)) do={
            :set constr "$constr:$[:pick $string $pos ($pos + 1)]"
        } else={
            :set constr "$constr$[:pick $string $pos ($pos + 1)]"
        }
    }
    :return $constr
}

{
:local v212 "\0E\26\20\01\22\02\F0\00\00\00\00\00\00\00\00\00\00\00\44\2B\FF\FE"

:local hexopt [$str2hex $v212]
:put $hexopt

:local arrayopt [$str2intarr $v212]
:put $arrayopt

:put "v4 mask length $($arrayopt->0)"

:put "v6 prefix length $($arrayopt->1)"

:put "IPv6 prefix $[$ipv6raw2format [:pick $hexopt 4 36]]"

:put "6to4 6rd tunnel endpoint $(0.0.0.0 + [[:parse ":return 0x$[:pick $hexopt 36 44]"]])"
}

result code

0E2620012202F00000000000000000000000442BFFFE
14;38;32;1;34;2;240;0;0;0;0;0;0;0;0;0;0;0;68;43;255;254
v4 mask length 14
v6 prefix length 38
IPv6 prefix 2001:2202:F000:0000:0000:0000:0000:0000
6to4 6rd tunnel endpoint 68.43.255.254
2001:2202:f000::/38 = from 2001:2202:f000::/38 to 2001:2202:f3ff:ffff:ffff:ffff:ffff:fffff

Who is online

Users browsing this forum: No registered users and 29 guests