Skip to content

Commit 2d97464

Browse files
authored
Merge pull request Place1#134 from DasSkelett/feature/block-inter-device-traffic
2 parents 04a37c7 + aa88ab7 commit 2d97464

File tree

4 files changed

+78
-36
lines changed

4 files changed

+78
-36
lines changed

cmd/serve/main.go

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -49,12 +49,13 @@ func Register(app *kingpin.Application) *servecmd {
4949
cli.Flag("wireguard-interface", "Set the wireguard interface name").Default("wg0").Envar("WG_WIREGUARD_INTERFACE").StringVar(&cmd.AppConfig.WireGuard.Interface)
5050
cli.Flag("wireguard-private-key", "Wireguard private key").Envar("WG_WIREGUARD_PRIVATE_KEY").StringVar(&cmd.AppConfig.WireGuard.PrivateKey)
5151
cli.Flag("wireguard-port", "The port that the Wireguard server will listen on").Envar("WG_WIREGUARD_PORT").Default("51820").IntVar(&cmd.AppConfig.WireGuard.Port)
52+
cli.Flag("vpn-allowed-ips", "A list of networks that VPN clients will be allowed to connect to via the VPN").Envar("WG_VPN_ALLOWED_IPS").Default("0.0.0.0/0", "::/0").StringsVar(&cmd.AppConfig.VPN.AllowedIPs)
5253
cli.Flag("vpn-cidr", "The network CIDR for the VPN").Envar("WG_VPN_CIDR").Default("10.44.0.0/24").StringVar(&cmd.AppConfig.VPN.CIDR)
5354
cli.Flag("vpn-cidrv6", "The IPv6 network CIDR for the VPN").Envar("WG_VPN_CIDRV6").Default("fd48:4c4:7aa9::/64").StringVar(&cmd.AppConfig.VPN.CIDRv6)
55+
cli.Flag("vpn-gateway-interface", "The gateway network interface (i.e. eth0)").Envar("WG_VPN_GATEWAY_INTERFACE").Default(detectDefaultInterface()).StringVar(&cmd.AppConfig.VPN.GatewayInterface)
5456
cli.Flag("vpn-nat44-enabled", "Enable or disable NAT of IPv6 traffic leaving through the gateway").Envar("WG_IPV4_NAT_ENABLED").Default("true").BoolVar(&cmd.AppConfig.VPN.NAT44)
5557
cli.Flag("vpn-nat66-enabled", "Enable or disable NAT of IPv6 traffic leaving through the gateway").Envar("WG_IPV6_NAT_ENABLED").Default("true").BoolVar(&cmd.AppConfig.VPN.NAT66)
56-
cli.Flag("vpn-gateway-interface", "The gateway network interface (i.e. eth0)").Envar("WG_VPN_GATEWAY_INTERFACE").Default(detectDefaultInterface()).StringVar(&cmd.AppConfig.VPN.GatewayInterface)
57-
cli.Flag("vpn-allowed-ips", "A list of networks that VPN clients will be allowed to connect to via the VPN").Envar("WG_VPN_ALLOWED_IPS").Default("0.0.0.0/0", "::/0").StringsVar(&cmd.AppConfig.VPN.AllowedIPs)
58+
cli.Flag("vpn-client-isolation", "Block or allow traffic between client devices").Envar("WG_VPN_CLIENT_ISOLATION").Default("false").BoolVar(&cmd.AppConfig.VPN.ClientIsolation)
5859
cli.Flag("dns-enabled", "Enable or disable the embedded dns proxy server (useful for development)").Envar("WG_DNS_ENABLED").Default("true").BoolVar(&cmd.AppConfig.DNS.Enabled)
5960
cli.Flag("dns-upstream", "An upstream DNS server to proxy DNS traffic to. Defaults to resolvconf with Cloudflare DNS as fallback").Envar("WG_DNS_UPSTREAM").StringsVar(&cmd.AppConfig.DNS.Upstream)
6061
cli.Flag("dns-domain", "A domain to serve configured device names authoritatively").Envar("WG_DNS_DOMAIN").StringVar(&cmd.AppConfig.DNS.Domain)
@@ -141,7 +142,17 @@ func (cmd *servecmd) Run() {
141142

142143
logrus.Infof("wireguard VPN network is %s", network.StringJoinIPNets(vpnip, vpnipv6))
143144

144-
if err := network.ConfigureForwarding(conf.VPN.GatewayInterface, conf.VPN.CIDR, conf.VPN.CIDRv6, conf.VPN.NAT44, conf.VPN.NAT66, conf.VPN.AllowedIPs); err != nil {
145+
options := network.ForwardingOptions{
146+
GatewayIface: conf.VPN.GatewayInterface,
147+
CIDR: conf.VPN.CIDR,
148+
CIDRv6: conf.VPN.CIDRv6,
149+
NAT44: conf.VPN.NAT44,
150+
NAT66: conf.VPN.NAT66,
151+
ClientIsolation: conf.VPN.ClientIsolation,
152+
AllowedIPs: conf.VPN.AllowedIPs,
153+
}
154+
155+
if err := network.ConfigureForwarding(options); err != nil {
145156
logrus.Error(err)
146157
return
147158
}

docs/2-configuration.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ Here's what you can configure:
3636
| `WG_VPN_CIDR` | `--vpn-cidr` | `vpn.cidr` | | `10.44.0.0/24` | The VPN IPv4 network range. VPN clients will be assigned IP addresses in this range. Set to `0` to disable IPv4. |
3737
| `WG_IPV4_NAT_ENABLED` | `--vpn-nat44-enabled` | `vpn.nat44` | | `true` | Disables NAT for IPv4 |
3838
| `WG_IPV6_NAT_ENABLED` | `--vpn-nat66-enabled` | `vpn.nat66` | | `true` | Disables NAT for IPv6 |
39+
| `WG_VPN_CLIENT_ISOLATION` | `--vpn-client-isolation` | `vpn.clientIsolation` | | `false` | BLock or allow traffic between client devices (client isolation) |
3940
| `WG_VPN_CIDRV6` | `--vpn-cidrv6` | `vpn.cidrv6` | | `fd48:4c4:7aa9::/64` | The VPN IPv6 network range. VPN clients will be assigned IP addresses in this range. Set to `0` to disable IPv6. |
4041
| `WG_VPN_GATEWAY_INTERFACE` | `--vpn-gateway-interface` | `vpn.gatewayInterface` | | _default gateway interface (e.g. eth0)_ | The VPN gateway interface. VPN client traffic will be forwarded to this interface. |
4142
| `WG_VPN_ALLOWED_IPS` | `--vpn-allowed-ips` | `vpn.allowedIPs` | | `0.0.0.0/0, ::/0` | Allowed IPs that clients may route through this VPN. This will be set in the client's WireGuard connection file and routing is also enforced by the server using iptables. |
@@ -54,5 +55,6 @@ wireguard:
5455
privateKey: "<some-key>"
5556
dns:
5657
upstream:
58+
- "2001:4860:4860::8888"
5759
- "8.8.8.8"
5860
```

internal/config/config.go

Lines changed: 14 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,12 @@ type AppConfig struct {
5454
} `yaml:"wireguard"`
5555
// Configure VPN related settings (networking)
5656
VPN struct {
57+
// The "AllowedIPs" for VPN clients.
58+
// This value will be included in client config
59+
// files and in server-side iptable rules
60+
// to enforce network access.
61+
// defaults to ["0.0.0.0/0", "::/0"]
62+
AllowedIPs []string `yaml:"allowedIPs"`
5763
// CIDR configures a network address space
5864
// that client (WireGuard peers) will be allocated
5965
// an IP address from
@@ -64,6 +70,11 @@ type AppConfig struct {
6470
// an IP address from
6571
// defaults to fd48:4c4:7aa9::/64
6672
CIDRv6 string `yaml:"cidrv6"`
73+
// GatewayInterface will be used in iptable forwarding
74+
// rules that send VPN traffic from clients to this interface
75+
// Most use-cases will want this interface to have access
76+
// to the outside internet
77+
GatewayInterface string `yaml:"gatewayInterface"`
6778
// NAT44 configures whether IPv4 traffic leaving
6879
// through the GatewayInterface should be masqueraded
6980
// defaults to true
@@ -73,17 +84,9 @@ type AppConfig struct {
7384
// masqueraded like IPv4 traffic
7485
// defaults to true
7586
NAT66 bool `yaml:"nat66"`
76-
// GatewayInterface will be used in iptable forwarding
77-
// rules that send VPN traffic from clients to this interface
78-
// Most use-cases will want this interface to have access
79-
// to the outside internet
80-
GatewayInterface string `yaml:"gatewayInterface"`
81-
// The "AllowedIPs" for VPN clients.
82-
// This value will be included in client config
83-
// files and in server-side iptable rules
84-
// to enforce network access.
85-
// defaults to ["0.0.0.0/0", "::/0"]
86-
AllowedIPs []string `yaml:"allowedIPs"`
87+
// ClientIsolation configures whether traffic between client devices will be blocked or allowed
88+
// defaults to false
89+
ClientIsolation bool `yaml:"clientIsolation"`
8790
} `yaml:"vpn"`
8891
// Configure the embedded DNS server
8992
DNS struct {

internal/network/network.go

Lines changed: 48 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -65,14 +65,25 @@ func SplitAddresses(addresses string) []string {
6565
return split
6666
}
6767

68-
func ConfigureForwarding(gatewayIface string, cidr, cidrv6 string, nat44, nat66 bool, allowedIPs []string) error {
68+
// ForwardingOptions contains all options used for configuring the firewall rules
69+
type ForwardingOptions struct {
70+
GatewayIface string
71+
CIDR, CIDRv6 string
72+
NAT44, NAT66 bool
73+
ClientIsolation bool
74+
AllowedIPs []string
75+
allowedIPv4s []string
76+
allowedIPv6s []string
77+
}
78+
79+
func ConfigureForwarding(options ForwardingOptions) error {
6980
// Networking configuration (iptables) configuration
7081
// to ensure that traffic from clients of the wireguard interface
7182
// is sent to the provided network interface
72-
allowedIPv4s := make([]string, 0, len(allowedIPs)/2)
73-
allowedIPv6s := make([]string, 0, len(allowedIPs)/2)
83+
allowedIPv4s := make([]string, 0, len(options.AllowedIPs)/2)
84+
allowedIPv6s := make([]string, 0, len(options.AllowedIPs)/2)
7485

75-
for _, allowedCIDR := range allowedIPs {
86+
for _, allowedCIDR := range options.AllowedIPs {
7687
parsedAddress, parsedNetwork, err := net.ParseCIDR(allowedCIDR)
7788
if err != nil {
7889
return errors.Wrap(err, "invalid cidr in AllowedIPs")
@@ -86,21 +97,23 @@ func ConfigureForwarding(gatewayIface string, cidr, cidrv6 string, nat44, nat66
8697
allowedIPv6s = append(allowedIPv6s, parsedNetwork.String())
8798
}
8899
}
100+
options.allowedIPv4s = allowedIPv4s
101+
options.allowedIPv6s = allowedIPv6s
89102

90-
if cidr != "" {
91-
if err := configureForwardingv4(gatewayIface, cidr, nat44, allowedIPv4s); err != nil {
103+
if options.CIDR != "" {
104+
if err := configureForwardingv4(options); err != nil {
92105
return err
93106
}
94107
}
95-
if cidrv6 != "" {
96-
if err := configureForwardingv6(gatewayIface, cidrv6, nat66, allowedIPv6s); err != nil {
108+
if options.CIDRv6 != "" {
109+
if err := configureForwardingv6(options); err != nil {
97110
return err
98111
}
99112
}
100113
return nil
101114
}
102115

103-
func configureForwardingv4(gatewayIface string, cidr string, nat44 bool, allowedIPs []string) error {
116+
func configureForwardingv4(options ForwardingOptions) error {
104117
ipt, err := iptables.NewWithProtocol(iptables.ProtocolIPv4)
105118
if err != nil {
106119
return errors.Wrap(err, "failed to init iptables")
@@ -128,27 +141,34 @@ func configureForwardingv4(gatewayIface string, cidr string, nat44 bool, allowed
128141
return errors.Wrap(err, "failed to append POSTROUTING rule to nat chain")
129142
}
130143

131-
for _, allowedCIDR := range allowedIPs {
132-
if err := ipt.AppendUnique("filter", "WG_ACCESS_SERVER_FORWARD", "-s", cidr, "-d", allowedCIDR, "-j", "ACCEPT"); err != nil {
144+
if options.ClientIsolation {
145+
// Reject inter-device traffic
146+
if err := ipt.AppendUnique("filter", "WG_ACCESS_SERVER_FORWARD", "-s", options.CIDR, "-d", options.CIDR, "-j", "REJECT"); err != nil {
147+
return errors.Wrap(err, "failed to set ip tables rule")
148+
}
149+
}
150+
// Accept client traffic for given allowed ips
151+
for _, allowedCIDR := range options.allowedIPv4s {
152+
if err := ipt.AppendUnique("filter", "WG_ACCESS_SERVER_FORWARD", "-s", options.CIDR, "-d", allowedCIDR, "-j", "ACCEPT"); err != nil {
133153
return errors.Wrap(err, "failed to set ip tables rule")
134154
}
135155
}
136156
// And reject everything else
137-
if err := ipt.AppendUnique("filter", "WG_ACCESS_SERVER_FORWARD", "-s", cidr, "-j", "REJECT"); err != nil {
157+
if err := ipt.AppendUnique("filter", "WG_ACCESS_SERVER_FORWARD", "-s", options.CIDR, "-j", "REJECT"); err != nil {
138158
return errors.Wrap(err, "failed to set ip tables rule")
139159
}
140160

141-
if gatewayIface != "" {
142-
if nat44 {
143-
if err := ipt.AppendUnique("nat", "WG_ACCESS_SERVER_POSTROUTING", "-s", cidr, "-o", gatewayIface, "-j", "MASQUERADE"); err != nil {
161+
if options.GatewayIface != "" {
162+
if options.NAT44 {
163+
if err := ipt.AppendUnique("nat", "WG_ACCESS_SERVER_POSTROUTING", "-s", options.CIDR, "-o", options.GatewayIface, "-j", "MASQUERADE"); err != nil {
144164
return errors.Wrap(err, "failed to set ip tables rule")
145165
}
146166
}
147167
}
148168
return nil
149169
}
150170

151-
func configureForwardingv6(gatewayIface string, cidrv6 string, nat66 bool, allowedIPs []string) error {
171+
func configureForwardingv6(options ForwardingOptions) error {
152172
ipt, err := iptables.NewWithProtocol(iptables.ProtocolIPv6)
153173
if err != nil {
154174
return errors.Wrap(err, "failed to init ip6tables")
@@ -174,20 +194,26 @@ func configureForwardingv6(gatewayIface string, cidrv6 string, nat66 bool, allow
174194
return errors.Wrap(err, "failed to append POSTROUTING rule to nat chain")
175195
}
176196

197+
if options.ClientIsolation {
198+
// Reject inter-device traffic
199+
if err := ipt.AppendUnique("filter", "WG_ACCESS_SERVER_FORWARD", "-s", options.CIDRv6, "-d", options.CIDRv6, "-j", "REJECT"); err != nil {
200+
return errors.Wrap(err, "failed to set ip tables rule")
201+
}
202+
}
177203
// Accept client traffic for given allowed ips
178-
for _, allowedCIDR := range allowedIPs {
179-
if err := ipt.AppendUnique("filter", "WG_ACCESS_SERVER_FORWARD", "-s", cidrv6, "-d", allowedCIDR, "-j", "ACCEPT"); err != nil {
204+
for _, allowedCIDR := range options.allowedIPv6s {
205+
if err := ipt.AppendUnique("filter", "WG_ACCESS_SERVER_FORWARD", "-s", options.CIDRv6, "-d", allowedCIDR, "-j", "ACCEPT"); err != nil {
180206
return errors.Wrap(err, "failed to set ip tables rule")
181207
}
182208
}
183209
// And reject everything else
184-
if err := ipt.AppendUnique("filter", "WG_ACCESS_SERVER_FORWARD", "-s", cidrv6, "-j", "REJECT"); err != nil {
210+
if err := ipt.AppendUnique("filter", "WG_ACCESS_SERVER_FORWARD", "-s", options.CIDRv6, "-j", "REJECT"); err != nil {
185211
return errors.Wrap(err, "failed to set ip tables rule")
186212
}
187213

188-
if gatewayIface != "" {
189-
if nat66 {
190-
if err := ipt.AppendUnique("nat", "WG_ACCESS_SERVER_POSTROUTING", "-s", cidrv6, "-o", gatewayIface, "-j", "MASQUERADE"); err != nil {
214+
if options.GatewayIface != "" {
215+
if options.NAT66 {
216+
if err := ipt.AppendUnique("nat", "WG_ACCESS_SERVER_POSTROUTING", "-s", options.CIDRv6, "-o", options.GatewayIface, "-j", "MASQUERADE"); err != nil {
191217
return errors.Wrap(err, "failed to set ip tables rule")
192218
}
193219
}

0 commit comments

Comments
 (0)