Skip to content

Commit

Permalink
Merge pull request #598 from Darkren/feature/secure-vpn
Browse files Browse the repository at this point in the history
Secure VPN
  • Loading branch information
jdknives authored Nov 12, 2020
2 parents 4b2708b + 0f90506 commit 5267aca
Show file tree
Hide file tree
Showing 8 changed files with 183 additions and 95 deletions.
2 changes: 2 additions & 0 deletions cmd/apps/vpn-server/vpn-server.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ var (
localPKStr = flag.String("pk", "", "Local PubKey")
localSKStr = flag.String("sk", "", "Local SecKey")
passcode = flag.String("passcode", "", "Passcode to authenticate connecting users")
secure = flag.Bool("secure", true, "Forbid connections from clients to server local network")
)

func main() {
Expand Down Expand Up @@ -73,6 +74,7 @@ func main() {

srvCfg := vpn.ServerConfig{
Passcode: *passcode,
Secure: *secure,
}
srv, err := vpn.NewServer(srvCfg, log)
if err != nil {
Expand Down
3 changes: 2 additions & 1 deletion internal/vpn/ip_generator.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@ type IPGenerator struct {
func NewIPGenerator() *IPGenerator {
return &IPGenerator{
ranges: []*subnetIPIncrementer{
newSubnetIPIncrementer([4]uint8{192, 168, 0, 0}, [4]uint8{192, 168, 255, 255}, 8),
// exclude some most commonly used addresses in local networks
newSubnetIPIncrementer([4]uint8{192, 168, 2, 0}, [4]uint8{192, 168, 255, 255}, 8),
newSubnetIPIncrementer([4]uint8{172, 16, 0, 0}, [4]uint8{172, 31, 255, 255}, 8),
newSubnetIPIncrementer([4]uint8{10, 0, 0, 0}, [4]uint8{10, 255, 255, 255}, 8),
},
Expand Down
65 changes: 65 additions & 0 deletions internal/vpn/os.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,71 @@ import (
"os/exec"
)

// LocalNetworkInterfaceIPs gets IPs of all local interfaces.
func LocalNetworkInterfaceIPs() ([]net.IP, error) {
ips, _, err := localNetworkInterfaceIPs("")
return ips, err
}

// NetworkInterfaceIPs gets IPs of network interface with name `name`.
func NetworkInterfaceIPs(name string) ([]net.IP, error) {
_, ifcIPs, err := localNetworkInterfaceIPs(name)
return ifcIPs, err
}

// localNetworkInterfaceIPs gets IPs of all local interfaces. Separately returns list of IPs
// of interface `ifcName`.
func localNetworkInterfaceIPs(ifcName string) ([]net.IP, []net.IP, error) {
var ifcIPs []net.IP

ifaces, err := net.Interfaces()
if err != nil {
return nil, nil, fmt.Errorf("error getting network interfaces: %w", err)
}

var ips []net.IP
for _, iface := range ifaces {
if iface.Flags&net.FlagUp == 0 {
continue // interface down
}
if iface.Flags&net.FlagLoopback != 0 {
continue // loopback interface
}

addrs, err := iface.Addrs()
if err != nil {
return nil, nil, fmt.Errorf("error getting addresses for interface %s: %w", iface.Name, err)
}

for _, addr := range addrs {
var ip net.IP
switch v := addr.(type) {
case *net.IPNet:
ip = v.IP
case *net.IPAddr:
ip = v.IP
}

if ip == nil || ip.IsLoopback() {
continue
}

ip = ip.To4()
if ip == nil {
continue // not an ipv4 address
}

ips = append(ips, ip)

if ifcName != "" && iface.Name == ifcName {
ifcIPs = append(ifcIPs, ip)
}
}
}

return ips, ifcIPs, nil
}

func parseCIDR(ipCIDR string) (ipStr, netmask string, err error) {
ip, net, err := net.ParseCIDR(ipCIDR)
if err != nil {
Expand Down
52 changes: 0 additions & 52 deletions internal/vpn/os_client.go

This file was deleted.

23 changes: 23 additions & 0 deletions internal/vpn/os_server.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,35 @@ package vpn

import (
"errors"
"net"
)

var (
errServerMethodsNotSupported = errors.New("server related methods are not supported for this OS")
)

// AllowSSH allows all SSH traffic (via default 22 port) between `src` and `dst`.
func AllowSSH(_, _ net.IP, _ []net.IP) error {
return errServerMethodsNotSupported
}

// BlockSSH blocks all SSH traffic (via default 22 port) between `src` and `dst`.
func BlockSSH(_, _ net.IP, _ []net.IP) error {
return errServerMethodsNotSupported
}

// AllowIPToLocalNetwork allows all the packets coming from `source`
// to private IP ranges.
func AllowIPToLocalNetwork(_, _ net.IP) error {
return errServerMethodsNotSupported
}

// BlockIPToLocalNetwork blocks all the packets coming from `source`
// to private IP ranges.
func BlockIPToLocalNetwork(_, _ net.IP) error {
return errServerMethodsNotSupported
}

// DefaultNetworkInterface fetches default network interface name.
func DefaultNetworkInterface() (string, error) {
return "", errServerMethodsNotSupported
Expand Down
25 changes: 25 additions & 0 deletions internal/vpn/os_server_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ package vpn
import (
"bytes"
"fmt"
"net"
"os/exec"
)

Expand All @@ -16,8 +17,32 @@ const (
setIPv6ForwardingCMDFmt = "sysctl -w net.ipv6.conf.all.forwarding=%s"
enableIPMasqueradingCMDFmt = "iptables -t nat -A POSTROUTING -o %s -j MASQUERADE"
disableIPMasqueradingCMDFmt = "iptables -t nat -D POSTROUTING -o %s -j MASQUERADE"
blockIPToLocalNetCMDFmt = "iptables -I FORWARD -d 192.168.0.0/16,172.16.0.0/12,10.0.0.0/8 -s %s -j DROP && iptables -I INPUT -d 192.168.0.0/16,172.16.0.0/12,10.0.0.0/8 -s %s -j DROP"
allowIPToLocalNetCMDFmt = "iptables -D FORWARD -d 192.168.0.0/16,172.16.0.0/12,10.0.0.0/8 -s %s -j DROP && iptables -D INPUT -d 192.168.0.0/16,172.16.0.0/12,10.0.0.0/8 -s %s -j DROP"
)

// AllowIPToLocalNetwork allows all the packets coming from `source`
// to private IP ranges.
func AllowIPToLocalNetwork(src, dst net.IP) error {
cmd := fmt.Sprintf(allowIPToLocalNetCMDFmt, src, src)
if err := exec.Command("sh", "-c", cmd).Run(); err != nil { //nolint:gosec
return fmt.Errorf("error running command %s: %w", cmd, err)
}

return nil
}

// BlockIPToLocalNetwork blocks all the packets coming from `source`
// to private IP ranges.
func BlockIPToLocalNetwork(src, dst net.IP) error {
cmd := fmt.Sprintf(blockIPToLocalNetCMDFmt, src, src)
if err := exec.Command("sh", "-c", cmd).Run(); err != nil { //nolint:gosec
return fmt.Errorf("error running command %s: %w", cmd, err)
}

return nil
}

// DefaultNetworkInterface fetches default network interface name.
func DefaultNetworkInterface() (string, error) {
outputBytes, err := exec.Command("sh", "-c", defaultNetworkInterfaceCMD).Output()
Expand Down
Loading

0 comments on commit 5267aca

Please sign in to comment.