Skip to content

Commit 9fe52b6

Browse files
committed
replace old NAT handling (parsing netstat-nat output) with own NAT parsing
1 parent f4aa3e5 commit 9fe52b6

File tree

1 file changed

+21
-129
lines changed

1 file changed

+21
-129
lines changed

netstat-nat.go

Lines changed: 21 additions & 129 deletions
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,16 @@ package main
22

33
import (
44
"github.com/dominikh/simple-router/conntrack"
5+
"github.com/dominikh/simple-router/lookup"
6+
"github.com/dominikh/simple-router/nat"
57

68
"flag"
79
"fmt"
8-
"net"
910
"os"
1011
"text/tabwriter"
1112
)
1213

13-
// -n: don't resolve host/portnames
14+
// TODO implement the following flags
1415
// -p <protocol> : display connections by protocol
1516
// -s <source-host> : display connections by source
1617
// -d <destination-host>: display connections by destination
@@ -26,65 +27,25 @@ var onlyRouted = flag.Bool("R", false, "Display only connections routed through
2627
var noResolve = flag.Bool("n", false, "Do not resolve hostnames") // TODO resolve port names as well
2728
var noHeader = flag.Bool("o", false, "Strip output header")
2829

29-
var (
30-
displaySNAT bool = true
31-
displayDNAT bool = true
32-
displayLocal bool = false
33-
displayRouted bool = false
34-
)
35-
36-
var localIPs = make([]*net.IPNet, 0)
37-
38-
func isLocalIP(ip net.IP) bool {
39-
for _, localIP := range localIPs {
40-
if localIP.IP.Equal(ip) {
41-
return true
42-
}
43-
}
44-
45-
return false
46-
}
47-
48-
func init() {
49-
addresses, err := net.InterfaceAddrs()
50-
if err != nil {
51-
panic(err)
52-
}
53-
54-
for _, address := range addresses {
55-
localIPs = append(localIPs, address.(*net.IPNet))
56-
}
57-
}
58-
5930
func main() {
6031
flag.Parse()
6132

33+
var which nat.Flag
34+
6235
if *onlySNAT {
63-
displaySNAT = true
64-
displayDNAT = false
65-
displayLocal = false
66-
displayRouted = false
36+
which = nat.SNAT
6737
}
6838

6939
if *onlyDNAT {
70-
displaySNAT = false
71-
displayDNAT = true
72-
displayLocal = false
73-
displayRouted = false
40+
which = nat.DNAT
7441
}
7542

7643
if *onlyLocal {
77-
displaySNAT = false
78-
displayDNAT = false
79-
displayLocal = true
80-
displayRouted = false
44+
which = nat.Local
8145
}
8246

8347
if *onlyRouted {
84-
displaySNAT = false
85-
displayDNAT = false
86-
displayLocal = false
87-
displayRouted = true
48+
which = nat.Routed
8849
}
8950

9051
flows, err := conntrack.Flows()
@@ -99,88 +60,19 @@ func main() {
9960
fmt.Fprintln(tabWriter, "Proto\tSource Address\tDestination Address\tState")
10061
}
10162

102-
for _, flow := range flows {
103-
if (displaySNAT && isSNAT(flow)) ||
104-
(displayDNAT && isDNAT(flow)) ||
105-
(displayLocal && isLocal(flow)) ||
106-
(displayRouted && isRouted(flow)) {
107-
108-
sHostname := resolve(flow.Original.Source)
109-
dHostname := resolve(flow.Original.Destination)
63+
natFlows := nat.GetNAT(flows, which)
64+
for _, flow := range natFlows {
65+
sHostname := lookup.Resolve(flow.Original.Source, *noResolve)
66+
dHostname := lookup.Resolve(flow.Original.Destination, *noResolve)
11067

111-
fmt.Fprintf(tabWriter, "%s\t%s:%d\t%s:%d\t%s\n",
112-
flow.Protocol,
113-
sHostname,
114-
flow.Original.SPort,
115-
dHostname,
116-
flow.Original.DPort,
117-
flow.State,
118-
)
119-
}
68+
fmt.Fprintf(tabWriter, "%s\t%s:%d\t%s:%d\t%s\n",
69+
flow.Protocol,
70+
sHostname,
71+
flow.Original.SPort,
72+
dHostname,
73+
flow.Original.DPort,
74+
flow.State,
75+
)
12076
}
12177
tabWriter.Flush()
12278
}
123-
124-
func resolve(ip net.IP) string {
125-
if *noResolve {
126-
return ip.String()
127-
}
128-
129-
lookup, err := net.LookupAddr(ip.String())
130-
if err == nil && len(lookup) > 0 {
131-
return lookup[0]
132-
}
133-
134-
return ip.String()
135-
}
136-
137-
func isSNAT(flow conntrack.Flow) bool {
138-
// SNATed flows should reply to our WAN IP, not a LAN IP.
139-
if flow.Original.Source.Equal(flow.Reply.Destination) {
140-
return false
141-
}
142-
143-
if !flow.Original.Destination.Equal(flow.Reply.Source) {
144-
return false
145-
}
146-
147-
return true
148-
}
149-
150-
func isDNAT(flow conntrack.Flow) bool {
151-
// Reply must go back to the source; Reply mustn't come from the WAN IP
152-
if flow.Original.Source.Equal(flow.Reply.Destination) && !flow.Original.Destination.Equal(flow.Reply.Source) {
153-
return true
154-
}
155-
156-
// Taken straight from original netstat-nat, labelled "DNAT (1 interface)"
157-
if !flow.Original.Source.Equal(flow.Reply.Source) && !flow.Original.Source.Equal(flow.Reply.Destination) && !flow.Original.Destination.Equal(flow.Reply.Source) && flow.Original.Destination.Equal(flow.Reply.Destination) {
158-
return true
159-
}
160-
161-
return false
162-
}
163-
164-
func isLocal(flow conntrack.Flow) bool {
165-
// no NAT
166-
if flow.Original.Source.Equal(flow.Reply.Destination) && flow.Original.Destination.Equal(flow.Reply.Source) {
167-
// At least one local address
168-
if isLocalIP(flow.Original.Source) || isLocalIP(flow.Original.Destination) || isLocalIP(flow.Reply.Source) || isLocalIP(flow.Reply.Destination) {
169-
return true
170-
}
171-
}
172-
173-
return false
174-
}
175-
176-
func isRouted(flow conntrack.Flow) bool {
177-
// no NAT
178-
if flow.Original.Source.Equal(flow.Reply.Destination) && flow.Original.Destination.Equal(flow.Reply.Source) {
179-
// No local addresses
180-
if !isLocalIP(flow.Original.Source) && !isLocalIP(flow.Original.Destination) && !isLocalIP(flow.Reply.Source) && !isLocalIP(flow.Reply.Destination) {
181-
return true
182-
}
183-
}
184-
185-
return false
186-
}

0 commit comments

Comments
 (0)