Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Secure VPN #598

Merged
merged 16 commits into from
Nov 12, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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