Add new nat rule with PEAR2 PHP

Hi guys, im scripting a new code to add nat rules on mikrotik, and i need some help :S

This is the code:

<?php //Listas desplegables echo "
"; //Peticion a la API $addRequest = $client->sendSync(new RouterOS\Request('/ip/firewall/nat/add')); echo ""; echo ""; echo ""; echo ""; echo ""; echo ""; echo ""; echo ""; echo "
AccionDireccion OrigenDireccion Destino ProtocoloPuerto OrigenPuerto SalidaAgregar
Src Dst 192.168.2.2 192.168.2.3 192.168.2.4 192.168.2.5 65.23.23.1 65.23.23.2 65.23.23.3 65.23.23.4 tcp udp gre icmpAgregar
";I need complete this code, but i dont know how.. P.D: I have this code too: ```text $addRequest = new RouterOS\Request('/ip/firewall/nat/add'); $addRequest->setArgument('chain', 'dstnat'); $addRequest->setArgument ('protocol', 'tcp'); $addRequest->setArgument('action', 'dst-nat'); $addRequest->setArgument('to-addresses', '192.168.2.3'); $addRequest->setArgument ('to-ports', '4562'); ``` But now, how i can convert this in a form? :S Thanks :slight_smile:

This line alone

$addRequest = $client->sendSync(new RouterOS\Request('/ip/firewall/nat/add')); 

doesn’t really add anything, since add requests need to actually contain the properties to be added.

You need to inspect the $_POST array, and convert it to the arguments.

Alternatively, you can just use the Util class, to which you can pass the $_POST array, MINUS anything that isn’t property/value pairs to be added. E.g.

<?php //Listas desplegables echo "
"; $util = new RouterOS\Util($client); $util->changeMenu('/ip/firewall/nat'); //Peticion a la API if (isset($_POST['add'])) { unset($_POST['add']); if ('' == $util->add($_POST)) { echo '
Failed to add rule
'; } } echo ""; echo ""; echo ""; echo ""; echo ""; echo ""; echo ""; echo ""; echo "
AccionDireccion OrigenDireccion Destino ProtocoloPuerto OrigenPuerto SalidaAgregar
Src Dst 192.168.2.2 192.168.2.3 192.168.2.4 192.168.2.5 65.23.23.1 65.23.23.2 65.23.23.3 65.23.23.4 tcp udp gre icmpAgregar
";(Though keep in mind that with that approach, you don't get the exact error messages from RouterOS - you only know if adding failed or not, but not why)

I update the code, and its working, but i have another problem.
In radio buttons, when i choose src(chain srcnat), the action should be src-nat, and when i choose dst(chain dstnat), the action should be dst-nat
When i create a nat rule, it creates with action accept :S

Well then, simply express what you just said in code, right before you do the adding, i.e.

//Peticion a la API
if (isset($_POST['add'])) {
    unset($_POST['add']);

    if (isset($_POST['chain'])) {
        if ('srcnat' === $_POST['chain']) {
            $_POST['action'] = 'src-nat';
        } elseif ('dstnat' === $_POST['chain']) {
            $_POST['action'] = 'dst-nat';
        }
    }
 
    if ('' == $util->add($_POST)) {
        echo '<div class="error">Failed to add rule</div>';
    }
} 

Hmm.. doesnt work, i post the complete code:

<?php use PEAR2\Net\RouterOS; // require_once 'pear2\src\PEAR2\Autoload.php'; require_once 'PEAR2_Net_RouterOS-1.0.0b4.phar'; $client = new RouterOS\Client('192.168.150.161', 'admin', 'admin'); if (isset($_POST['act'])) { foreach ($_POST['act'] as $act => $itemID) { //Limit the action only to known ones, for security's sake if (in_array($act, array('set', 'remove'))) { $actionRequest = new RouterOS\Request("/ip/firewall/nat/{$act}"); $actionRequest->setArgument('numbers', $itemID); if ('set' === $act) { foreach ($_POST[$itemID] as $name => $value) { $actionRequest->setArgument($name, $value); } } $responses = $client->sendSync($actionRequest); $errors = $responses->getAllOfType(RouterOS\Response::TYPE_ERROR); if (0 === count($errors)) { echo "
'{$act}' OK!
"; } else { echo '
    '; foreach ($errors as $error) { echo '
  • ' . $error('message') . '
  • '; } echo '
'; } } } } // Tabla echo ""; echo ""; echo ""; // Peticion a la API $responses = $client->sendSync(new RouterOS\Request('/ip/firewall/nat/print')); foreach ($responses as $response) { if ($response->getType() === RouterOS\Response::TYPE_DATA) { $id = $response('.id'); echo ""; echo ""; echo ""; echo ""; echo ""; echo ""; echo ""; //Boton Modificar echo ""; echo ""; } } echo "
AccionDireccion OrigenDireccion DestinoProtocoloPuerto OrigenPuerto SalidaModificar/Eliminar
".$response('protocol'). " -------------- ddp egp encap etherip ggp gre hmp icmp icmpv6 idpr-cmtp igmp ipencap ipip ipsec-ah ipsec-esp ipv6 ipv6-frag ipv6-nonxt ipv6-opts ipv6-route iso-tp4 l2tp ospf pim pup rdp rspf rsvp st tcp udp vmtp vrrp xns-idp xtp ! Modificar"; //Boton Borrar echo "Eliminar
"; //Agregar Nat Rule echo "
"; $util = new RouterOS\Util($client); $util->changeMenu('/ip/firewall/nat'); //Peticion a la API if (isset($_POST['add'])) { unset($_POST['add']); if (isset($_POST['chain'])) { if ('srcnat' === $_POST['chain']) { $_POST['action'] = 'src-nat'; } elseif ('dstnat' === $_POST['chain']) { $_POST['action'] = 'dst-nat'; } } if ('' == $util->add($_POST)) { echo '
Failed to add rule
'; } } echo ""; echo ""; echo ""; echo ""; echo ""; echo ""; echo ""; echo ""; echo "
AccionDireccion OrigenDireccion Destino ProtocoloPuerto OrigenPuerto SalidaAgregar
Src Dst 192.168.2.2 192.168.2.3 192.168.2.4 192.168.2.5 65.23.23.1 65.23.23.2 65.23.23.3 65.23.23.4 tcp udp gre icmpAgregar
"; ?>and the tables is something like that:

http://gyazo.com/5a871e913478c54f35b1435208b9e161

I need add nat rules without values too, without protocol, src and dst ports :S
The first table, with nat rules print, works very well, thanks to u too, but the new table to add new rules no :S

Wait… you’re writing both forms on a single PHP page?

That complicates things a little bit, as you need to unambigiously select one action to do upon submitting, since both codes would be executed.

You could perhaps rename the “add” button to “act” and have its value be “add”. After that, combining the two processings is a piece of cake:

<?php use PEAR2\Net\RouterOS; // require_once 'pear2\src\PEAR2\Autoload.php'; require_once 'PEAR2_Net_RouterOS-1.0.0b4.phar'; $client = new RouterOS\Client('192.168.150.161', 'admin', 'admin'); if (isset($_POST['act'])) { foreach ($_POST['act'] as $act => $itemID) { //Limit the action only to known ones, for security's sake if (in_array($act, array('set', 'remove', 'add'))) { $actionRequest = new RouterOS\Request("/ip/firewall/nat/{$act}"); if ('add' !== $act) { $actionRequest->setArgument('numbers', $itemID); } if ('set' === $act || 'add' === $act) { if (isset($_POST[$itemID]['chain'])) { if ('srcnat' === $_POST[$itemID]['chain']) { $_POST[$itemID]['action'] = 'src-nat'; } elseif ('dstnat' === $_POST[$itemID]['chain']) { $_POST[$itemID]['action'] = 'dst-nat'; } } foreach ($_POST[$itemID] as $name => $value) { $actionRequest->setArgument($name, $value); } } $responses = $client->sendSync($actionRequest); $errors = $responses->getAllOfType(RouterOS\Response::TYPE_ERROR); if (0 === count($errors)) { echo "
'{$act}' OK!
"; } else { echo '
    '; foreach ($errors as $error) { echo '
  • ' . $error('message') . '
  • '; } echo '
'; } } } } // Tabla echo ""; echo ""; echo ""; // Peticion a la API $responses = $client->sendSync(new RouterOS\Request('/ip/firewall/nat/print')); foreach ($responses as $response) { if ($response->getType() === RouterOS\Response::TYPE_DATA) { $id = $response('.id'); echo ""; echo ""; echo ""; echo ""; echo ""; echo ""; echo ""; //Boton Modificar echo ""; echo ""; } } echo "
AccionDireccion OrigenDireccion DestinoProtocoloPuerto OrigenPuerto SalidaModificar/Eliminar
".$response('protocol'). " -------------- ddp egp encap etherip ggp gre hmp icmp icmpv6 idpr-cmtp igmp ipencap ipip ipsec-ah ipsec-esp ipv6 ipv6-frag ipv6-nonxt ipv6-opts ipv6-route iso-tp4 l2tp ospf pim pup rdp rspf rsvp st tcp udp vmtp vrrp xns-idp xtp ! Modificar"; //Boton Borrar echo "Eliminar
"; //Agregar Nat Rule echo "
"; echo ""; echo ""; echo ""; echo ""; echo ""; echo ""; echo ""; echo ""; echo ""; echo "
AccionDireccion OrigenDireccion Destino ProtocoloPuerto OrigenPuerto SalidaAgregar
Src Dst 192.168.2.2 192.168.2.3 192.168.2.4 192.168.2.5 65.23.23.1 65.23.23.2 65.23.23.3 65.23.23.4 tcp udp gre icmpAgregar
"; ?>

The script looks good, but when i try add a new rule, doesnt work and alerts me (“failure: no chain specified”)

Apparently, an empty key name is not allowed… try the above now (where I’ve added a “*” in front of all fields on adding; I’ve also corrected the form itself - it should start before the table, and I’ve made the add form separate to avoid sending everything else when adding).

It adds the rule with ‘accept’ action, and when i refresh the page, it adds again the same rule..

Opps. I missed altering the “chain” pre-processing bit…

I’ve fixed it above.

Working, but we still have 2 problems, when i refresh after add, it add a new same rule, and i cant add new rule without protocol and ports. In winbox we can..

For the duplicate adding issue, replace

            if (0 === count($errors)) {
                echo "<div>'{$act}' OK!</div>"; 

with

            if (0 === count($errors)) {
                header('Location: http://' . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI']);
                return; 

The redirect will force the browser to go back to the same page, but without any $_POST data following it. We do this only on success, since you may otherwise try to retry a previously failed request by refreshing the page.

An for the adding without empty values issue, replace

                foreach ($_POST[$itemID] as $name => $value) {
                    $actionRequest->setArgument($name, $value);
                } 

with

                foreach ($_POST[$itemID] as $name => $value) {
                    if ('' != $value) {
                        $actionRequest->setArgument($name, $value);
                    }
                } 

Perfect, its working very well, thanks you so much again :slight_smile: