Add a generic NAT table: port forward, source NAT, masquerade
router.firewall.nat replaces the dnat/toPort/hairpin fields of the filter rules. Filter rules gain natOnly, and may use wan with log and rate limit in the web UI. The Firewall page edits the NAT table and can add the matching allow rule. Settings schema 1 (migrations/1.jq) converts old forwards. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01AeFqV9dZrK6nipHkPfyM4F
This commit is contained in:
@@ -40,11 +40,11 @@
|
||||
<input type="hidden" name="rows" value="{{len .Rows}}">
|
||||
<div class="scroll">
|
||||
<table>
|
||||
<tr><th>From zone</th><th>From address</th><th>From port</th><th>To zone</th><th>To address</th><th>To port</th><th>Protocol</th><th>Remove</th></tr>
|
||||
<tr><th>From zone</th><th>From address</th><th>From port</th><th>To zone</th><th>To address</th><th>To port</th><th>Protocol</th><th title="only connections that a port forward translated">Forwarded only</th><th>Log</th><th>Rate limit</th><th>Remove</th></tr>
|
||||
{{range $i, $r := .Rows}}
|
||||
<tr>
|
||||
<td><select name="rule.{{$i}}.from"><option value=""></option>
|
||||
{{range $.Data.Zones}}<option value="{{.}}" {{if eq . $r.From}}selected{{end}}>{{.}}</option>{{end}}
|
||||
{{range $.Data.FromZones}}<option value="{{.}}" {{if eq . $r.From}}selected{{end}}>{{.}}</option>{{end}}
|
||||
</select></td>
|
||||
<td><input name="rule.{{$i}}.sources" value="{{$r.Sources}}" size="16" spellcheck="false" placeholder="any"></td>
|
||||
<td><input name="rule.{{$i}}.sourceports" value="{{$r.SourcePorts}}" size="8" placeholder="any"></td>
|
||||
@@ -56,50 +56,62 @@
|
||||
<td><select name="rule.{{$i}}.protocol">
|
||||
{{range $p := list "any" "tcp" "udp" "icmp"}}<option value="{{$p}}" {{if eq $p $r.Protocol}}selected{{end}}>{{$p}}</option>{{end}}
|
||||
</select></td>
|
||||
<td><input type="checkbox" name="rule.{{$i}}.natonly" {{if $r.NATOnly}}checked{{end}}></td>
|
||||
<td><input type="checkbox" name="rule.{{$i}}.log" {{if $r.Log}}checked{{end}}></td>
|
||||
<td><input name="rule.{{$i}}.ratelimit" value="{{$r.RateLimit}}" size="9" placeholder="none"></td>
|
||||
<td>{{if or $r.From $r.To}}<input type="checkbox" name="rule.{{$i}}.remove">{{end}}</td>
|
||||
</tr>
|
||||
{{range $f := list "from" "sources" "sourcePorts" "to" "destination" "ports" "protocol"}}{{with index $e (printf "rule[%d].%s" $i $f)}}<tr><td colspan="8" class="field-error">{{$f}}: {{.}}</td></tr>{{end}}{{end}}
|
||||
{{range $f := list "from" "sources" "sourcePorts" "to" "destination" "ports" "protocol" "ratelimit"}}{{with index $e (printf "rule[%d].%s" $i $f)}}<tr><td colspan="11" class="field-error">{{$f}}: {{.}}</td></tr>{{end}}{{end}}
|
||||
{{end}}
|
||||
</table>
|
||||
</div>
|
||||
<p class="hint">Fill in the last row to add a rule. Addresses (several separated by commas) are IPv4 or IPv6, single or CIDR;
|
||||
to address is one address or network. Ports (tcp and udp only): <code>22, 443, 5000-5100</code>.</p>
|
||||
to address is one address or network. Ports (tcp and udp only): <code>22, 443, 5000-5100</code>.
|
||||
From <code>wan</code> (the internet) a rule must name the address inside, the protocol and the ports, and only lets
|
||||
traffic through; a port forward is set up below. <strong>Forwarded only</strong> limits a rule to connections that a
|
||||
port forward translated. Rate limit caps new connections per sender, like <code>10/minute</code>.</p>
|
||||
</fieldset>
|
||||
|
||||
<fieldset>
|
||||
<legend>From the internet</legend>
|
||||
<input type="hidden" name="forwards" value="{{len .Forwards}}">
|
||||
<legend>Address translation (NAT)</legend>
|
||||
<input type="hidden" name="nats" value="{{len .NATs}}">
|
||||
<div class="scroll">
|
||||
<table>
|
||||
<tr><th>Protocol</th><th>Public port</th><th>To zone</th><th>To address</th><th>To port</th><th>Only from</th><th>Port forward</th><th>Hairpin</th><th>Log</th><th>Rate limit</th><th>Remove</th></tr>
|
||||
{{range $i, $r := .Forwards}}
|
||||
<tr><th>Type</th><th>From zone</th><th>From address</th><th>Sent to</th><th>Protocol</th><th>Port</th><th>To zone</th><th>Translate to</th><th>To port</th><th>Hairpin</th><th>Also allow</th><th>Remove</th></tr>
|
||||
{{range $i, $r := .NATs}}
|
||||
<tr>
|
||||
<td><select name="fwd.{{$i}}.protocol">
|
||||
{{range $p := list "tcp" "udp" "icmp"}}<option value="{{$p}}" {{if eq $p $r.Protocol}}selected{{end}}>{{$p}}</option>{{end}}
|
||||
<td><select name="nat.{{$i}}.type">
|
||||
{{range $p := list "dnat" "snat" "masquerade"}}<option value="{{$p}}" {{if eq $p $r.Type}}selected{{end}}>{{if eq $p "dnat"}}port forward{{else if eq $p "snat"}}source NAT{{else}}masquerade{{end}}</option>{{end}}
|
||||
</select></td>
|
||||
<td><input name="fwd.{{$i}}.ports" value="{{$r.Ports}}" size="10" placeholder="443"></td>
|
||||
<td><select name="fwd.{{$i}}.to"><option value=""></option>
|
||||
{{range $.Data.Zones}}<option value="{{.}}" {{if eq . $r.To}}selected{{end}}>{{.}}</option>{{end}}
|
||||
<td><select name="nat.{{$i}}.from"><option value="">any</option>
|
||||
{{range $.Data.FromZones}}<option value="{{.}}" {{if eq . $r.From}}selected{{end}}>{{.}}</option>{{end}}
|
||||
</select></td>
|
||||
<td><input name="fwd.{{$i}}.destination" value="{{$r.Destination}}" size="16" spellcheck="false" placeholder="192.168.10.5"></td>
|
||||
<td><input name="fwd.{{$i}}.toport" value="{{$r.ToPort}}" size="6" placeholder="same"></td>
|
||||
<td><input name="fwd.{{$i}}.sources" value="{{$r.Sources}}" size="14" spellcheck="false" placeholder="anywhere"></td>
|
||||
<td><input type="checkbox" name="fwd.{{$i}}.nat" {{if $r.NAT}}checked{{end}}></td>
|
||||
<td><input type="checkbox" name="fwd.{{$i}}.hairpin" {{if $r.Hairpin}}checked{{end}}></td>
|
||||
<td><input type="checkbox" name="fwd.{{$i}}.log" {{if $r.Log}}checked{{end}}></td>
|
||||
<td><input name="fwd.{{$i}}.ratelimit" value="{{$r.RateLimit}}" size="9" placeholder="none"></td>
|
||||
<td>{{if or $r.Ports $r.Destination}}<input type="checkbox" name="fwd.{{$i}}.remove">{{end}}</td>
|
||||
<td><input name="nat.{{$i}}.sources" value="{{$r.Sources}}" size="14" spellcheck="false" placeholder="any"></td>
|
||||
<td><input name="nat.{{$i}}.destination" value="{{$r.Destination}}" size="14" spellcheck="false" placeholder="the router"></td>
|
||||
<td><select name="nat.{{$i}}.protocol">
|
||||
{{range $p := list "any" "tcp" "udp" "icmp"}}<option value="{{$p}}" {{if eq $p $r.Protocol}}selected{{end}}>{{$p}}</option>{{end}}
|
||||
</select></td>
|
||||
<td><input name="nat.{{$i}}.ports" value="{{$r.Ports}}" size="10" placeholder="443"></td>
|
||||
<td><select name="nat.{{$i}}.to"><option value=""></option>
|
||||
{{range $.Data.FromZones}}<option value="{{.}}" {{if eq . $r.To}}selected{{end}}>{{.}}</option>{{end}}
|
||||
</select></td>
|
||||
<td><input name="nat.{{$i}}.toaddress" value="{{$r.ToAddress}}" size="14" spellcheck="false" placeholder="192.168.10.5"></td>
|
||||
<td><input name="nat.{{$i}}.toport" value="{{$r.ToPort}}" size="6" placeholder="same"></td>
|
||||
<td><input type="checkbox" name="nat.{{$i}}.hairpin" {{if $r.Hairpin}}checked{{end}}></td>
|
||||
<td>{{if or $r.ToAddress $r.Ports}}{{if $r.Allow}}<input type="checkbox" name="nat.{{$i}}.allow" checked>{{else}}<input type="checkbox" name="nat.{{$i}}.allow">{{end}}{{end}}</td>
|
||||
<td>{{if or $r.ToAddress $r.Ports $r.To}}<input type="checkbox" name="nat.{{$i}}.remove">{{end}}</td>
|
||||
</tr>
|
||||
{{range $f := list "protocol" "ports" "to" "destination" "toport" "sources" "hairpin" "ratelimit"}}{{with index $e (printf "fwd[%d].%s" $i $f)}}<tr><td colspan="11" class="field-error">{{$f}}: {{.}}</td></tr>{{end}}{{end}}
|
||||
{{range $f := list "type" "from" "sources" "destination" "protocol" "ports" "to" "toaddress" "toport" "hairpin"}}{{with index $e (printf "nat[%d].%s" $i $f)}}<tr><td colspan="12" class="field-error">{{$f}}: {{.}}</td></tr>{{end}}{{end}}
|
||||
{{end}}
|
||||
</table>
|
||||
</div>
|
||||
<p class="hint">Everything from the internet is blocked unless listed here. A <strong>port forward</strong> sends tcp or udp
|
||||
traffic for the router's public IPv4 address to one host inside (to address is that host; to port only if it differs,
|
||||
with a single public port); the sender's address is kept. Without it the rule just lets traffic through to an address
|
||||
or network inside, for IPv6 or for a public range. <strong>Hairpin</strong> lets your LANs use the forward through the
|
||||
router's public address. Rate limit caps new connections per sender, like <code>10/minute</code>.
|
||||
Fill in the last row to add one.</p>
|
||||
<p class="hint"><strong>Port forward:</strong> traffic from the zone (<code>wan</code> is the internet) addressed to the router
|
||||
(or to the address in <em>Sent to</em>) on these ports goes to the host in <em>Translate to</em>, in zone <em>To zone</em>;
|
||||
the sender's address is kept. <em>Also allow</em> adds the filter rule that lets it through (without it the firewall still
|
||||
blocks it). <em>Hairpin</em> lets your LANs use a forward from the internet through the router's public address.<br>
|
||||
<strong>Masquerade</strong> and <strong>source NAT</strong> rewrite where traffic from the zone (or any zone) leaves through
|
||||
<em>To zone</em>: masquerade with the outgoing interface's address, source NAT with the address in <em>Translate to</em>.
|
||||
Internet-enabled LANs are already masqueraded out the uplink. Fill in the last row to add one.</p>
|
||||
</fieldset>
|
||||
<button>Save</button>
|
||||
</form>
|
||||
|
||||
Reference in New Issue
Block a user