Bläddra i källkod

feat(vpn): implement configurable dns option

Mustafa Arici 8 år sedan
förälder
incheckning
8bbbb27401
12 ändrade filer med 142 tillägg och 77 borttagningar
  1. 2 1
      api/rpc.go
  2. 1 1
      bindata/bindata.go
  3. 14 1
      cmd/ovpm/vpn.go
  4. 3 0
      const.go
  5. 7 7
      net_test.go
  6. 45 28
      pb/vpn.pb.go
  7. 2 0
      pb/vpn.proto
  8. 6 0
      pb/vpn.swagger.json
  9. 1 1
      template/server.conf.tmpl
  10. 10 10
      user_test.go
  11. 39 16
      vpn.go
  12. 12 12
      vpn_test.go

+ 2 - 1
api/rpc.go

@@ -187,6 +187,7 @@ func (s *VPNService) Status(ctx context.Context, req *pb.VPNStatusRequest) (*pb.
 		Net:          server.GetNet(),
 		Mask:         server.GetMask(),
 		CreatedAt:    server.GetCreatedAt(),
+		DNS:          server.GetDNS(),
 	}
 	return &response, nil
 }
@@ -203,7 +204,7 @@ func (s *VPNService) Init(ctx context.Context, req *pb.VPNInitRequest) (*pb.VPNI
 		proto = ovpm.UDPProto
 	}
 
-	if err := ovpm.Init(req.Hostname, req.Port, proto, req.IPBlock); err != nil {
+	if err := ovpm.Init(req.Hostname, req.Port, proto, req.IPBlock, req.DNS); err != nil {
 		logrus.Errorf("server can not be created: %v", err)
 	}
 	return &pb.VPNInitResponse{}, nil

Filskillnaden har hållts tillbaka eftersom den är för stor
+ 1 - 1
bindata/bindata.go


+ 14 - 1
cmd/ovpm/vpn.go

@@ -37,6 +37,7 @@ var vpnStatusCommand = cli.Command{
 		table.Append([]string{"Network", res.Net})
 		table.Append([]string{"Netmask", res.Mask})
 		table.Append([]string{"Created At", res.CreatedAt})
+		table.Append([]string{"DNS", res.DNS})
 		table.Render()
 
 		return nil
@@ -65,6 +66,10 @@ var vpnInitCommand = cli.Command{
 			Name:  "net, n",
 			Usage: fmt.Sprintf("VPN network to give clients IP addresses from, in the CIDR form (default: %s)", ovpm.DefaultVPNNetwork),
 		},
+		cli.StringFlag{
+			Name:  "dns, d",
+			Usage: fmt.Sprintf("DNS server to push to clients (default: %s)", ovpm.DefaultVPNDNS),
+		},
 	},
 	Action: func(c *cli.Context) error {
 		action = "vpn:init"
@@ -96,6 +101,14 @@ var vpnInitCommand = cli.Command{
 			os.Exit(1)
 		}
 
+		dns := c.String("dns")
+		if dns != "" && !govalidator.IsIPv4(dns) {
+			fmt.Println("--dns takes an IPv4 address. e.g. 8.8.8.8")
+			fmt.Println()
+			fmt.Println(cli.ShowSubcommandHelp(c))
+			os.Exit(1)
+		}
+
 		conn := getConn(c.GlobalString("daemon-port"))
 		defer conn.Close()
 		vpnSvc := pb.NewVPNServiceClient(conn)
@@ -115,7 +128,7 @@ var vpnInitCommand = cli.Command{
 			okayResponses := []string{"y", "Y", "yes", "Yes", "YES"}
 			nokayResponses := []string{"n", "N", "no", "No", "NO"}
 			if stringInSlice(response, okayResponses) {
-				if _, err := vpnSvc.Init(context.Background(), &pb.VPNInitRequest{Hostname: hostname, Port: port, Protopref: proto, IPBlock: ipblock}); err != nil {
+				if _, err := vpnSvc.Init(context.Background(), &pb.VPNInitRequest{Hostname: hostname, Port: port, Protopref: proto, IPBlock: ipblock, DNS: dns}); err != nil {
 					logrus.Errorf("server can not be initialized: %v", err)
 					os.Exit(1)
 					return err

+ 3 - 0
const.go

@@ -13,6 +13,9 @@ const (
 	// DefaultVPNNetwork is the default OpenVPN network to use.
 	DefaultVPNNetwork = "10.9.0.0/24"
 
+	// DefaultVPNDNS is the default DNS to push to clients.
+	DefaultVPNDNS = "8.8.8.8"
+
 	etcBasePath = "/etc/ovpm/"
 	varBasePath = "/var/db/ovpm/"
 

+ 7 - 7
net_test.go

@@ -9,7 +9,7 @@ func TestVPNCreateNewNetwork(t *testing.T) {
 	setupTestCase()
 	CreateDB("sqlite3", ":memory:")
 	defer db.Cease()
-	Init("localhost", "", UDPProto, "")
+	Init("localhost", "", UDPProto, "", "")
 
 	// Prepare:
 	// Test:
@@ -56,7 +56,7 @@ func TestVPNDeleteNetwork(t *testing.T) {
 	setupTestCase()
 	CreateDB("sqlite3", ":memory:")
 	defer db.Cease()
-	Init("localhost", "", UDPProto, "")
+	Init("localhost", "", UDPProto, "", "")
 
 	// Prepare:
 	// Test:
@@ -94,7 +94,7 @@ func TestVPNGetNetwork(t *testing.T) {
 	setupTestCase()
 	CreateDB("sqlite3", ":memory:")
 	defer db.Cease()
-	Init("localhost", "", UDPProto, "")
+	Init("localhost", "", UDPProto, "", "")
 
 	// Prepare:
 	// Test:
@@ -129,7 +129,7 @@ func TestVPNGetAllNetworks(t *testing.T) {
 	setupTestCase()
 	CreateDB("sqlite3", ":memory:")
 	defer db.Cease()
-	Init("localhost", "", UDPProto, "")
+	Init("localhost", "", UDPProto, "", "")
 
 	// Prepare:
 	// Test:
@@ -175,7 +175,7 @@ func TestNetAssociate(t *testing.T) {
 	setupTestCase()
 	CreateDB("sqlite3", ":memory:")
 	defer db.Cease()
-	Init("localhost", "", UDPProto, "")
+	Init("localhost", "", UDPProto, "", "")
 
 	// Prepare:
 	// Test:
@@ -220,7 +220,7 @@ func TestNetDissociate(t *testing.T) {
 	setupTestCase()
 	CreateDB("sqlite3", ":memory:")
 	defer db.Cease()
-	err := Init("localhost", "", UDPProto, "")
+	err := Init("localhost", "", UDPProto, "", "")
 	if err != nil {
 		t.Fatal(err)
 	}
@@ -273,7 +273,7 @@ func TestNetGetAssociatedUsers(t *testing.T) {
 	setupTestCase()
 	CreateDB("sqlite3", ":memory:")
 	defer db.Cease()
-	Init("localhost", "", UDPProto, "")
+	Init("localhost", "", UDPProto, "", "")
 
 	// Prepare:
 	// Test:

+ 45 - 28
pb/vpn.pb.go

@@ -55,6 +55,7 @@ type VPNInitRequest struct {
 	Port      string   `protobuf:"bytes,2,opt,name=Port" json:"Port,omitempty"`
 	Protopref VPNProto `protobuf:"varint,3,opt,name=Protopref,enum=pb.VPNProto" json:"Protopref,omitempty"`
 	IPBlock   string   `protobuf:"bytes,4,opt,name=IPBlock" json:"IPBlock,omitempty"`
+	DNS       string   `protobuf:"bytes,5,opt,name=DNS" json:"DNS,omitempty"`
 }
 
 func (m *VPNInitRequest) Reset()                    { *m = VPNInitRequest{} }
@@ -90,6 +91,13 @@ func (m *VPNInitRequest) GetIPBlock() string {
 	return ""
 }
 
+func (m *VPNInitRequest) GetDNS() string {
+	if m != nil {
+		return m.DNS
+	}
+	return ""
+}
+
 type VPNStatusResponse struct {
 	Name         string `protobuf:"bytes,1,opt,name=Name" json:"Name,omitempty"`
 	SerialNumber string `protobuf:"bytes,2,opt,name=SerialNumber" json:"SerialNumber,omitempty"`
@@ -101,6 +109,7 @@ type VPNStatusResponse struct {
 	Mask         string `protobuf:"bytes,8,opt,name=Mask" json:"Mask,omitempty"`
 	CreatedAt    string `protobuf:"bytes,9,opt,name=CreatedAt" json:"CreatedAt,omitempty"`
 	Proto        string `protobuf:"bytes,10,opt,name=Proto" json:"Proto,omitempty"`
+	DNS          string `protobuf:"bytes,11,opt,name=DNS" json:"DNS,omitempty"`
 }
 
 func (m *VPNStatusResponse) Reset()                    { *m = VPNStatusResponse{} }
@@ -178,6 +187,13 @@ func (m *VPNStatusResponse) GetProto() string {
 	return ""
 }
 
+func (m *VPNStatusResponse) GetDNS() string {
+	if m != nil {
+		return m.DNS
+	}
+	return ""
+}
+
 type VPNInitResponse struct {
 }
 
@@ -302,32 +318,33 @@ var _VPNService_serviceDesc = grpc.ServiceDesc{
 func init() { proto.RegisterFile("vpn.proto", fileDescriptor1) }
 
 var fileDescriptor1 = []byte{
-	// 423 bytes of a gzipped FileDescriptorProto
-	0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x74, 0x92, 0xcf, 0x72, 0xd3, 0x30,
-	0x10, 0xc6, 0xb1, 0xe3, 0x3a, 0xf1, 0x4e, 0x26, 0x38, 0xdb, 0x02, 0x22, 0xd3, 0x43, 0x47, 0xa7,
-	0x4c, 0x0e, 0xf1, 0x50, 0x6e, 0xbd, 0x95, 0x00, 0xd3, 0x1e, 0x30, 0x9a, 0x14, 0x72, 0x57, 0x8a,
-	0xe8, 0x78, 0x9a, 0x4a, 0x42, 0x52, 0x72, 0x87, 0x03, 0x2f, 0xc0, 0x4b, 0xf0, 0x3e, 0xbc, 0x02,
-	0x0f, 0xc2, 0x48, 0x76, 0xfe, 0x98, 0x99, 0xde, 0xbe, 0xfd, 0xad, 0x77, 0xbd, 0xfb, 0xad, 0x20,
-	0xdb, 0x68, 0x39, 0xd5, 0x46, 0x39, 0x85, 0xb1, 0x5e, 0x8e, 0x4e, 0xef, 0x94, 0xba, 0x5b, 0x89,
-	0x82, 0xeb, 0xaa, 0xe0, 0x52, 0x2a, 0xc7, 0x5d, 0xa5, 0xa4, 0xad, 0xbf, 0xa0, 0x08, 0xf9, 0x82,
-	0x95, 0x37, 0x8e, 0xbb, 0xb5, 0x9d, 0x8b, 0x6f, 0x6b, 0x61, 0x1d, 0xfd, 0x19, 0xc1, 0x60, 0xc1,
-	0xca, 0x6b, 0x59, 0xb9, 0x06, 0xe1, 0x08, 0x7a, 0x57, 0xca, 0x3a, 0xc9, 0x1f, 0x04, 0x89, 0xce,
-	0xa2, 0x71, 0x36, 0xdf, 0xc5, 0x88, 0x90, 0x30, 0x65, 0x1c, 0x89, 0x03, 0x0f, 0x1a, 0x27, 0x90,
-	0x31, 0xdf, 0x5f, 0x1b, 0xf1, 0x95, 0x74, 0xce, 0xa2, 0xf1, 0xe0, 0xbc, 0x3f, 0xd5, 0xcb, 0xe9,
-	0x82, 0x95, 0x81, 0xcf, 0xf7, 0x69, 0x24, 0xd0, 0xbd, 0x66, 0x6f, 0x56, 0xea, 0xf6, 0x9e, 0x24,
-	0xa1, 0xc5, 0x36, 0xa4, 0xdf, 0x63, 0x18, 0x1e, 0x4c, 0x67, 0xb5, 0x92, 0x36, 0xfc, 0xaf, 0xdc,
-	0xcf, 0x11, 0x34, 0x52, 0xe8, 0xdf, 0x08, 0x53, 0xf1, 0x55, 0xb9, 0x7e, 0x58, 0x0a, 0xd3, 0xcc,
-	0xd2, 0x62, 0xad, 0x1d, 0x3a, 0x8f, 0xec, 0x90, 0x1c, 0xec, 0x80, 0x90, 0xcc, 0x84, 0x71, 0xe4,
-	0xa8, 0x66, 0x5e, 0xe3, 0x73, 0x48, 0x67, 0x97, 0x81, 0xa6, 0x81, 0x36, 0x11, 0xe6, 0xd0, 0x29,
-	0x85, 0x23, 0xdd, 0x00, 0xbd, 0xf4, 0xd5, 0x1f, 0xb8, 0xbd, 0x27, 0xbd, 0xba, 0xda, 0x6b, 0x3c,
-	0x85, 0x6c, 0x66, 0x04, 0x77, 0xe2, 0xcb, 0xa5, 0x23, 0x59, 0x48, 0xec, 0x01, 0x9e, 0xc0, 0x51,
-	0x30, 0x85, 0x40, 0xc8, 0xd4, 0x01, 0x1d, 0xc2, 0xd3, 0xdd, 0x2d, 0x6a, 0x03, 0x26, 0x63, 0xe8,
-	0x6d, 0x7d, 0x44, 0x80, 0xb4, 0xfc, 0xc8, 0xe6, 0xef, 0xde, 0xe7, 0x4f, 0xb0, 0x0b, 0x9d, 0xcf,
-	0x6f, 0x59, 0x1e, 0x79, 0xf1, 0x69, 0xc6, 0xf2, 0xf8, 0xfc, 0x77, 0x04, 0xe0, 0x0d, 0x14, 0x66,
-	0x53, 0xdd, 0x0a, 0x64, 0x90, 0xd6, 0x5e, 0xe2, 0x49, 0x73, 0x8c, 0xd6, 0xe1, 0x47, 0xcf, 0xfe,
-	0xa3, 0xf5, 0xff, 0xe8, 0xcb, 0x1f, 0x7f, 0xfe, 0xfe, 0x8a, 0x8f, 0xe9, 0xa0, 0xd8, 0xbc, 0x2a,
-	0x36, 0x5a, 0x16, 0x36, 0xe4, 0x2f, 0xa2, 0x09, 0x5e, 0x41, 0xe2, 0x47, 0x43, 0x6c, 0x2a, 0x0f,
-	0xde, 0xcc, 0xe8, 0xb8, 0xc5, 0x9a, 0x5e, 0x2f, 0x42, 0xaf, 0x21, 0xed, 0x6f, 0x7b, 0x55, 0xb2,
-	0x72, 0x17, 0xd1, 0x64, 0x99, 0x86, 0xf7, 0xf8, 0xfa, 0x5f, 0x00, 0x00, 0x00, 0xff, 0xff, 0x93,
-	0x52, 0x74, 0x1b, 0xbe, 0x02, 0x00, 0x00,
+	// 434 bytes of a gzipped FileDescriptorProto
+	0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x74, 0x52, 0xcd, 0x6e, 0xd3, 0x40,
+	0x10, 0xc6, 0x8e, 0xeb, 0xc4, 0x43, 0x14, 0x9c, 0x69, 0x81, 0x25, 0xea, 0xa1, 0xf2, 0x29, 0xca,
+	0x21, 0x16, 0xe5, 0xd6, 0x5b, 0x49, 0x41, 0xed, 0x81, 0x65, 0x95, 0x40, 0xee, 0x4e, 0x59, 0x2a,
+	0xab, 0xe9, 0xee, 0xb2, 0xbb, 0xc9, 0x03, 0xf0, 0x0a, 0xbd, 0xf0, 0x08, 0xbc, 0x0f, 0xaf, 0xc0,
+	0x83, 0x20, 0x8f, 0x9d, 0x3f, 0xa4, 0xde, 0xbe, 0xf9, 0xc6, 0xf3, 0xf9, 0x9b, 0x6f, 0x07, 0x92,
+	0xb5, 0x51, 0x63, 0x63, 0xb5, 0xd7, 0x18, 0x9a, 0xc5, 0xe0, 0xf4, 0x4e, 0xeb, 0xbb, 0xa5, 0xcc,
+	0x0b, 0x53, 0xe6, 0x85, 0x52, 0xda, 0x17, 0xbe, 0xd4, 0xca, 0xd5, 0x5f, 0x64, 0x08, 0xe9, 0x5c,
+	0xf0, 0x99, 0x2f, 0xfc, 0xca, 0x4d, 0xe5, 0x8f, 0x95, 0x74, 0x3e, 0xfb, 0x15, 0x40, 0x6f, 0x2e,
+	0xf8, 0x8d, 0x2a, 0x7d, 0x43, 0xe1, 0x00, 0x3a, 0xd7, 0xda, 0x79, 0x55, 0x3c, 0x48, 0x16, 0x9c,
+	0x05, 0xc3, 0x64, 0xba, 0xad, 0x11, 0x21, 0x12, 0xda, 0x7a, 0x16, 0x12, 0x4f, 0x18, 0x47, 0x90,
+	0x88, 0x4a, 0xdf, 0x58, 0xf9, 0x9d, 0xb5, 0xce, 0x82, 0x61, 0xef, 0xbc, 0x3b, 0x36, 0x8b, 0xf1,
+	0x5c, 0x70, 0xe2, 0xa7, 0xbb, 0x36, 0x32, 0x68, 0xdf, 0x88, 0xf7, 0x4b, 0x7d, 0x7b, 0xcf, 0x22,
+	0x92, 0xd8, 0x94, 0x98, 0x42, 0xeb, 0x8a, 0xcf, 0xd8, 0x11, 0xb1, 0x15, 0xcc, 0x1e, 0x43, 0xe8,
+	0xef, 0xf9, 0x75, 0x46, 0x2b, 0x47, 0x0e, 0xf8, 0xce, 0x19, 0x61, 0xcc, 0xa0, 0x3b, 0x93, 0xb6,
+	0x2c, 0x96, 0x7c, 0xf5, 0xb0, 0x90, 0xb6, 0x71, 0x77, 0xc0, 0x1d, 0x6c, 0xd5, 0x7a, 0x62, 0xab,
+	0x68, 0x6f, 0x2b, 0x84, 0x68, 0x22, 0xad, 0x6f, 0x0c, 0x11, 0xc6, 0x57, 0x10, 0x4f, 0x2e, 0x89,
+	0x8d, 0x89, 0x6d, 0xaa, 0xca, 0x3b, 0x97, 0x9e, 0xb5, 0x6b, 0xef, 0x5c, 0xd2, 0xf4, 0xa7, 0xc2,
+	0xdd, 0xb3, 0x4e, 0x3d, 0x5d, 0x61, 0x3c, 0x85, 0x64, 0x62, 0x65, 0xe1, 0xe5, 0xb7, 0x4b, 0xcf,
+	0x12, 0x6a, 0xec, 0x08, 0x3c, 0x81, 0x23, 0x8a, 0x89, 0x01, 0x75, 0xea, 0x62, 0x93, 0xca, 0xf3,
+	0x5d, 0x2a, 0x7d, 0x78, 0xb1, 0x7d, 0xaf, 0x3a, 0x92, 0xd1, 0x10, 0x3a, 0x9b, 0xac, 0x11, 0x20,
+	0xe6, 0x9f, 0xc5, 0xf4, 0xc3, 0xc7, 0xf4, 0x19, 0xb6, 0xa1, 0xf5, 0xf5, 0x4a, 0xa4, 0x41, 0x05,
+	0xbe, 0x4c, 0x44, 0x1a, 0x9e, 0xff, 0x0e, 0x00, 0xaa, 0x48, 0xa5, 0x5d, 0x97, 0xb7, 0x12, 0x05,
+	0xc4, 0x75, 0xba, 0x78, 0xd2, 0x3c, 0xd8, 0xc1, 0x71, 0x0c, 0x5e, 0xfe, 0xc7, 0xd6, 0xff, 0xcb,
+	0xde, 0xfc, 0xfc, 0xf3, 0xf7, 0x31, 0x3c, 0xce, 0x7a, 0xf9, 0xfa, 0x6d, 0xbe, 0x36, 0x2a, 0x77,
+	0xd4, 0xbf, 0x08, 0x46, 0x78, 0x0d, 0x51, 0x65, 0x0d, 0xb1, 0x99, 0xdc, 0xbb, 0xab, 0xc1, 0xf1,
+	0x01, 0xd7, 0x68, 0xbd, 0x26, 0xad, 0x7e, 0xd6, 0xdd, 0x68, 0x95, 0xaa, 0xf4, 0x17, 0xc1, 0x68,
+	0x11, 0xd3, 0xcd, 0xbe, 0xfb, 0x17, 0x00, 0x00, 0xff, 0xff, 0x72, 0x2f, 0x46, 0x3c, 0xe2, 0x02,
+	0x00, 0x00,
 }

+ 2 - 0
pb/vpn.proto

@@ -16,6 +16,7 @@ message VPNInitRequest {
   string Port = 2;
   VPNProto Protopref = 3;
   string IPBlock = 4;
+  string DNS = 5;
 }
 
 service VPNService {
@@ -42,5 +43,6 @@ message VPNStatusResponse {
   string Mask = 8;
   string CreatedAt = 9;
   string Proto = 10;
+  string DNS = 11;
 }
 message VPNInitResponse {}

+ 6 - 0
pb/vpn.swagger.json

@@ -83,6 +83,9 @@
         },
         "IPBlock": {
           "type": "string"
+        },
+        "DNS": {
+          "type": "string"
         }
       }
     },
@@ -133,6 +136,9 @@
         },
         "Proto": {
           "type": "string"
+        },
+        "DNS": {
+          "type": "string"
         }
       }
     }

+ 1 - 1
template/server.conf.tmpl

@@ -182,7 +182,7 @@ crl-verify {{ .CRLPath }}
 # The addresses below refer to the public
 # DNS servers provided by opendns.com.
 ;push "dhcp-option DNS 208.67.222.222"
-push "dhcp-option DNS 8.8.8.8"
+push "dhcp-option DNS {{ .DNS }}"
 
 # Uncomment this directive to allow different
 # clients to be able to "see" each other.

+ 10 - 10
user_test.go

@@ -13,7 +13,7 @@ func TestCreateNewUser(t *testing.T) {
 	// Initialize:
 	db := ovpm.CreateDB("sqlite3", ":memory:")
 	defer db.Cease()
-	ovpm.Init("localhost", "", ovpm.UDPProto, "")
+	ovpm.Init("localhost", "", ovpm.UDPProto, "", "")
 	server, _ := ovpm.GetServerInstance()
 
 	// Prepare:
@@ -84,7 +84,7 @@ func TestUserUpdate(t *testing.T) {
 	// Initialize:
 	db := ovpm.CreateDB("sqlite3", ":memory:")
 	defer db.Cease()
-	ovpm.Init("localhost", "", ovpm.UDPProto, "")
+	ovpm.Init("localhost", "", ovpm.UDPProto, "", "")
 
 	// Prepare:
 	username := "testUser"
@@ -122,7 +122,7 @@ func TestUserPasswordCorrect(t *testing.T) {
 	// Initialize:
 	db := ovpm.CreateDB("sqlite3", ":memory:")
 	defer db.Cease()
-	ovpm.Init("localhost", "", ovpm.UDPProto, "")
+	ovpm.Init("localhost", "", ovpm.UDPProto, "", "")
 
 	// Prepare:
 	initialPassword := "g00dp@ssW0rd9"
@@ -139,7 +139,7 @@ func TestUserPasswordReset(t *testing.T) {
 	// Initialize:
 	db := ovpm.CreateDB("sqlite3", ":memory:")
 	defer db.Cease()
-	ovpm.Init("localhost", "", ovpm.UDPProto, "")
+	ovpm.Init("localhost", "", ovpm.UDPProto, "", "")
 
 	// Prepare:
 	initialPassword := "g00dp@ssW0rd9"
@@ -166,7 +166,7 @@ func TestUserDelete(t *testing.T) {
 	// Initialize:
 	db := ovpm.CreateDB("sqlite3", ":memory:")
 	defer db.Cease()
-	ovpm.Init("localhost", "", ovpm.UDPProto, "")
+	ovpm.Init("localhost", "", ovpm.UDPProto, "", "")
 
 	// Prepare:
 	username := "testUser"
@@ -204,7 +204,7 @@ func TestUserGet(t *testing.T) {
 	// Initialize:
 	db := ovpm.CreateDB("sqlite3", ":memory:")
 	defer db.Cease()
-	ovpm.Init("localhost", "", ovpm.UDPProto, "")
+	ovpm.Init("localhost", "", ovpm.UDPProto, "", "")
 
 	// Prepare:
 	username := "testUser"
@@ -228,7 +228,7 @@ func TestUserGetAll(t *testing.T) {
 	// Initialize:
 	db := ovpm.CreateDB("sqlite3", ":memory:")
 	defer db.Cease()
-	ovpm.Init("localhost", "", ovpm.UDPProto, "")
+	ovpm.Init("localhost", "", ovpm.UDPProto, "", "")
 	count := 5
 
 	// Prepare:
@@ -266,14 +266,14 @@ func TestUserRenew(t *testing.T) {
 	// Initialize:
 	db := ovpm.CreateDB("sqlite3", ":memory:")
 	defer db.Cease()
-	ovpm.Init("localhost", "", ovpm.UDPProto, "")
+	ovpm.Init("localhost", "", ovpm.UDPProto, "", "")
 
 	// Prepare:
 	user, _ := ovpm.CreateNewUser("user", "1234", false, 0, true)
 
 	// Test:
 	// Re initialize the server.
-	ovpm.Init("example.com", "3333", ovpm.UDPProto, "") // This causes implicit Renew() on every user in the system.
+	ovpm.Init("example.com", "3333", ovpm.UDPProto, "", "") // This causes implicit Renew() on every user in the system.
 
 	// Fetch user back.
 	fetchedUser, _ := ovpm.GetUser(user.GetUsername())
@@ -288,7 +288,7 @@ func TestUserIPAllocator(t *testing.T) {
 	// Initialize:
 	db := ovpm.CreateDB("sqlite3", ":memory:")
 	defer db.Cease()
-	ovpm.Init("localhost", "", ovpm.UDPProto, "")
+	ovpm.Init("localhost", "", ovpm.UDPProto, "", "")
 
 	// Prepare:
 

+ 39 - 16
vpn.go

@@ -52,6 +52,7 @@ type dbServerModel struct {
 	Net      string // VPN network.
 	Mask     string // VPN network mask.
 	CRL      string // Certificate Revocation List
+	DNS      string // DNS servers to push to the clients.
 }
 
 // Server represents VPN server.
@@ -134,25 +135,19 @@ func (s *Server) GetCRL() string {
 	return s.CRL
 }
 
+// GetDNS returns vpn server's dns.
+func (s *Server) GetDNS() string {
+	if s.DNS != "" {
+		return s.DNS
+	}
+	return DefaultVPNDNS
+}
+
 // GetCreatedAt returns server's created at.
 func (s *Server) GetCreatedAt() string {
 	return s.CreatedAt.Format(time.UnixDate)
 }
 
-type _VPNServerConfig struct {
-	CertPath     string
-	KeyPath      string
-	CACertPath   string
-	CAKeyPath    string
-	CCDPath      string
-	CRLPath      string
-	DHParamsPath string
-	Net          string
-	Mask         string
-	Port         string
-	Proto        string
-}
-
 // Init regenerates keys and certs for a Root CA, gets initial settings for the VPN server
 // and saves them in the database.
 //
@@ -163,11 +158,15 @@ type _VPNServerConfig struct {
 //
 // Please note that, Init is potentially destructive procedure, it will cause invalidation of
 // existing .ovpn profiles of the current users. So it should be used carefully.
-func Init(hostname string, port string, proto string, ipblock string) error {
+func Init(hostname string, port string, proto string, ipblock string, dns string) error {
 	if port == "" {
 		port = DefaultVPNPort
 	}
 
+	if dns == "" {
+		dns = DefaultVPNDNS
+	}
+
 	switch proto {
 	case "":
 		proto = UDPProto
@@ -222,6 +221,10 @@ func Init(hostname string, port string, proto string, ipblock string) error {
 		return fmt.Errorf("validation error: hostname:`%s` should be either an ip address or a FQDN", hostname)
 	}
 
+	if !govalidator.IsIPv4(dns) {
+		return fmt.Errorf("validation error: dns:`%s` should be an ip address", dns)
+	}
+
 	ca, err := pki.NewCA()
 	if err != nil {
 		return fmt.Errorf("can not create ca creds: %s", err)
@@ -246,6 +249,7 @@ func Init(hostname string, port string, proto string, ipblock string) error {
 		CAKey:        ca.Key,
 		Net:          ipnet.IP.To4().String(),
 		Mask:         net.IP(ipnet.Mask).To4().String(),
+		DNS:          dns,
 	}
 
 	db.Create(&serverInstance)
@@ -515,9 +519,27 @@ func emitServerConf() error {
 		proto = serverInstance.Proto
 	}
 
+	dns := DefaultVPNDNS
+	if serverInstance.DNS != "" {
+		dns = serverInstance.DNS
+	}
+
 	var result bytes.Buffer
 
-	server := _VPNServerConfig{
+	server := struct {
+		CertPath     string
+		KeyPath      string
+		CACertPath   string
+		CAKeyPath    string
+		CCDPath      string
+		CRLPath      string
+		DHParamsPath string
+		Net          string
+		Mask         string
+		Port         string
+		Proto        string
+		DNS          string
+	}{
 		CertPath:     _DefaultCertPath,
 		KeyPath:      _DefaultKeyPath,
 		CACertPath:   _DefaultCACertPath,
@@ -529,6 +551,7 @@ func emitServerConf() error {
 		Mask:         dbServer.Mask,
 		Port:         port,
 		Proto:        proto,
+		DNS:          dns,
 	}
 	data, err := bindata.Asset("template/server.conf.tmpl")
 	if err != nil {

+ 12 - 12
vpn_test.go

@@ -35,13 +35,13 @@ func TestVPNInit(t *testing.T) {
 	}
 
 	// Wrongfully initialize server.
-	err := Init("localhost", "asdf", UDPProto, "")
+	err := Init("localhost", "asdf", UDPProto, "", "")
 	if err == nil {
 		t.Fatalf("error is expected to be not nil but it's nil instead")
 	}
 
 	// Initialize the server.
-	Init("localhost", "", UDPProto, "")
+	Init("localhost", "", UDPProto, "", "")
 
 	// Check database if the database has no server.
 	var server2 dbServerModel
@@ -61,7 +61,7 @@ func TestVPNDeinit(t *testing.T) {
 
 	// Prepare:
 	// Initialize the server.
-	Init("localhost", "", UDPProto, "")
+	Init("localhost", "", UDPProto, "", "")
 	u, err := CreateNewUser("user", "p", false, 0, true)
 	if err != nil {
 		t.Fatal(err)
@@ -122,7 +122,7 @@ func TestVPNIsInitialized(t *testing.T) {
 	}
 
 	// Initialize the server.
-	Init("localhost", "", UDPProto, "")
+	Init("localhost", "", UDPProto, "", "")
 
 	// Isn't initialized?
 	if !IsInitialized() {
@@ -152,7 +152,7 @@ func TestVPNGetServerInstance(t *testing.T) {
 	}
 
 	// Initialize server.
-	Init("localhost", "", UDPProto, "")
+	Init("localhost", "", UDPProto, "", "")
 
 	server, err = GetServerInstance()
 
@@ -172,7 +172,7 @@ func TestVPNDumpsClientConfig(t *testing.T) {
 	setupTestCase()
 	CreateDB("sqlite3", ":memory:")
 	defer db.Cease()
-	Init("localhost", "", UDPProto, "")
+	Init("localhost", "", UDPProto, "", "")
 
 	// Prepare:
 	user, _ := CreateNewUser("user", "password", false, 0, true)
@@ -194,7 +194,7 @@ func TestVPNDumpClientConfig(t *testing.T) {
 	setupTestCase()
 	CreateDB("sqlite3", ":memory:")
 	defer db.Cease()
-	Init("localhost", "", UDPProto, "")
+	Init("localhost", "", UDPProto, "", "")
 
 	// Prepare:
 	noGW := false
@@ -262,7 +262,7 @@ func TestVPNGetSystemCA(t *testing.T) {
 	}
 
 	// Initialize system.
-	Init("localhost", "", UDPProto, "")
+	Init("localhost", "", UDPProto, "", "")
 
 	ca, err = GetSystemCA()
 	if err != nil {
@@ -302,7 +302,7 @@ func TestVPNStartVPNProc(t *testing.T) {
 	}
 
 	// Initialize OVPM server.
-	Init("localhost", "", UDPProto, "")
+	Init("localhost", "", UDPProto, "", "")
 
 	// Call start again..
 	StartVPNProc()
@@ -318,7 +318,7 @@ func TestVPNStopVPNProc(t *testing.T) {
 	setupTestCase()
 	CreateDB("sqlite3", ":memory:")
 	defer db.Cease()
-	Init("localhost", "", UDPProto, "")
+	Init("localhost", "", UDPProto, "", "")
 
 	// Prepare:
 	vpnProc.Start()
@@ -342,7 +342,7 @@ func TestVPNRestartVPNProc(t *testing.T) {
 	// Init:
 	CreateDB("sqlite3", ":memory:")
 	defer db.Cease()
-	Init("localhost", "", UDPProto, "")
+	Init("localhost", "", UDPProto, "", "")
 
 	// Prepare:
 
@@ -371,7 +371,7 @@ func TestVPNEmit(t *testing.T) {
 	setupTestCase()
 	CreateDB("sqlite3", ":memory:")
 	defer db.Cease()
-	Init("localhost", "", UDPProto, "")
+	Init("localhost", "", UDPProto, "", "")
 
 	// Prepare:
 

Vissa filer visades inte eftersom för många filer har ändrats