Reputation: 13
Just wondering if anyone can help me. I'm currently building a pfsense firewall, which uses VPN connections to secure the traffic. The VPN provider does provide a port forwarding mechanism, but the incoming port number changes every hour. I have a script which allows me to discover the new port, but I need a scripted way to modify the port forward settings in the firewall to match.
A snippet of the firewall config file that controls this is as follows: input.xml
:
<?xml version="1.0"?>
<pfsense>
<nat>
<rule>
<source>
<any/>
</source>
<destination>
<any/>
<port>53400</port>
</destination>
<protocol>tcp/udp</protocol>
<target>192.168.0.15</target>
<local-port>53400</local-port>
<interface>opt2</interface>
<descr><![CDATA[Torrent]]></descr>
<associated-rule-id>nat_52d81d2dc904f5.77023355</associated-rule-id>
<created>
<time>1389894957</time>
<username>[email protected]</username>
</created>
<updated>
<time>1389980696</time>
<username>[email protected]</username>
</updated>
</rule>
</nat>
<filter>
<rule>
<id/>
<type>pass</type>
<interface>opt2</interface>
<ipprotocol>inet</ipprotocol>
<tag/>
<tagged/>
<max/>
<max-src-nodes/>
<max-src-conn/>
<max-src-states/>
<statetimeout/>
<statetype>keep state</statetype>
<os/>
<protocol>tcp/udp</protocol>
<source>
<any/>
</source>
<destination>
<address>192.168.0.15</address>
<port>53400</port>
</destination>
<log/>
<descr><![CDATA[NAT Torrent]]></descr>
<associated-rule-id>nat_52d81d2dc904f5.77023355</associated-rule-id>
<created>
<time>1389894957</time>
<username>NAT Port Forward</username>
</created>
<updated>
<time>1389899075</time>
<username>[email protected]</username>
</updated>
</rule>
</filter>
</pfsense>
In the XML above, we have the two parts which comprise a port forward rule for pfsense. The part enclosed in the <nat>
section is the port forward. The section in the <rule>
is an interface specific incoming firewall rule. Both have to be modified for the new port forward setting to be effective.
I was thinking to use xmlstarlet to modify the config file, using the <descr>
as my key for identifying which sections to change.
I'm aware that you can have data like:
<username><![CDATA[name]]></username>
<password><![CDATA[password]]></password>
<dbname><![CDATA[name]]></dbname>
and modify it with:
xml ed -P -O -L \
-u '//username/text()' -v 'something' \
-u '//password/text()' -v 'somethingelse' \
-u '//dbname/text()' -v 'somethingdifferent' \
file.xml
and also that you can have something like: sample.xml
:
<objects>
<object>
<name>Foo</name>
<constant1>10</constant1>
<constant2>20</constant2>
</object>
<object>
<name>Bar</name>
<constant1>15</constant1>
<constant2>40</constant2>
</object>
</objects>
and update attributes with:
xmlstarlet ed -u '//object[name="Foo"]/const1' -v 18 sample.xml
However, I'm struggling to merge the two, so that I have a single statement which matches <descr>="Torrent"
and then updates the relevant <port>
and <local-port>
attributes.
Any help with a suitable xmlstarlet command would be much appreciated.
Upvotes: 1
Views: 1613
Reputation: 5027
$ xmlstarlet ed \
-u '//rule[descr="Torrent"]/destination/port' -v 1111 \
-u '//rule[descr="Torrent"]/local-port' -v 2222 \
input.xml |
xmlstarlet format --indent-spaces 4 > output.xml
$ diff input.xml output.xml
10c10
< <port>53400</port>
---
> <port>1111</port>
14c14
< <local-port>53400</local-port>
---
> <local-port>2222</local-port>
28d27
<
Upvotes: 4