From 55acfb6b25901d285b0635c5087fda42f4e055e6 Mon Sep 17 00:00:00 2001 From: Mustafa Arici Date: Sat, 2 Sep 2017 11:09:28 +0300 Subject: [PATCH 01/10] refactor: major refactor of all service - Improve API by improving the wording of the methods. - Utilize composition to provide abstraction. - Group together related methods under the same struct. --- api/rpc.go | 19 ++++---- db.go | 32 ++++++++----- db_test.go | 10 ++-- net.go | 81 ++++++++++++++++++------------- net_test.go | 55 +++++++++++---------- user.go | 120 +++++++++++++++++++++++++--------------------- user_test.go | 62 +++++++++++------------- vpn.go | 131 ++++++++++++++++++++++++++++++++++++++++----------- vpn_test.go | 56 +++++++++++----------- 9 files changed, 336 insertions(+), 230 deletions(-) diff --git a/api/rpc.go b/api/rpc.go index 8f2c697..c5c5f3f 100644 --- a/api/rpc.go +++ b/api/rpc.go @@ -2,7 +2,6 @@ package api import ( "os" - "time" "google.golang.org/grpc" @@ -178,16 +177,16 @@ func (s *VPNService) Status(ctx context.Context, req *pb.VPNStatusRequest) (*pb. } response := pb.VPNStatusResponse{ - Name: server.Name, - SerialNumber: server.SerialNumber, - Hostname: server.Hostname, - Port: server.Port, + Name: server.GetServerName(), + SerialNumber: server.GetSerialNumber(), + Hostname: server.GetHostname(), + Port: server.GetPort(), Proto: server.GetProto(), - Cert: server.Cert, - CACert: server.CACert, - Net: server.Net, - Mask: server.Mask, - CreatedAt: server.CreatedAt.Format(time.UnixDate), + Cert: server.GetCert(), + CACert: server.GetCACert(), + Net: server.GetNet(), + Mask: server.GetMask(), + CreatedAt: server.GetCreatedAt(), } return &response, nil } diff --git a/db.go b/db.go index d8cc2c1..249e0b0 100644 --- a/db.go +++ b/db.go @@ -8,30 +8,40 @@ import ( _ "github.com/jinzhu/gorm/dialects/sqlite" ) -var db *gorm.DB +var db *DB -// SetupDB prepares database for use. +// DB represents a persistent storage. +type DB struct { + *gorm.DB +} + +// CreateDB prepares and returns new storage. // // It should be run at the start of the program. -func SetupDB(dialect string, args ...interface{}) { +func CreateDB(dialect string, args ...interface{}) *DB { if len(args) > 0 && args[0] == "" { args[0] = _DefaultDBPath } var err error - db, err = gorm.Open(dialect, args...) + + dbase, err := gorm.Open(dialect, args...) if err != nil { logrus.Fatalf("couldn't open sqlite database %v: %v", args, err) } - db.AutoMigrate(&DBUser{}) - db.AutoMigrate(&DBServer{}) - db.AutoMigrate(&DBRevoked{}) - db.AutoMigrate(&DBNetwork{}) + dbase.AutoMigrate(&dbUserModel{}) + dbase.AutoMigrate(&dbServerModel{}) + dbase.AutoMigrate(&dbRevokedModel{}) + dbase.AutoMigrate(&dbNetworkModel{}) + + dbPTR := &DB{DB: dbase} + db = dbPTR + return dbPTR } -// CeaseDB closes the database. +// Cease closes the database. // // It should be run at the exit of the program. -func CeaseDB() { - db.Close() +func (db *DB) Cease() { + db.DB.Close() } diff --git a/db_test.go b/db_test.go index fd42b36..586344b 100644 --- a/db_test.go +++ b/db_test.go @@ -10,7 +10,7 @@ func TestDBSetup(t *testing.T) { // Test: // Create database. - SetupDB("sqlite3", ":memory:") + CreateDB("sqlite3", ":memory:") // Is database created? if db == nil { @@ -23,15 +23,15 @@ func TestDBCease(t *testing.T) { Testing = true // Prepare: - SetupDB("sqlite3", ":memory:") - user := DBUser{Username: "testUser"} + CreateDB("sqlite3", ":memory:") + user := dbUserModel{Username: "testUser"} db.Save(&user) // Test: // Close database. - CeaseDB() + db.Cease() - var users []DBUser + var users []dbUserModel db.Find(&users) // Is length zero? diff --git a/net.go b/net.go index 0c3f40c..46a7a0a 100644 --- a/net.go +++ b/net.go @@ -63,6 +63,7 @@ func (nt NetworkType) String() string { return "UNDEFINEDNET" } +// Description gives description about the network type. func (nt NetworkType) Description() string { for _, v := range networkTypes { if v.Type == nt { @@ -72,21 +73,26 @@ func (nt NetworkType) Description() string { return "UNDEFINEDNET" } -// DBNetwork is database model for external networks on the VPN server. -type DBNetwork struct { +// dbNetworkModel is database model for external networks on the VPN server. +type dbNetworkModel struct { gorm.Model ServerID uint - Server DBServer + Server dbServerModel Name string `gorm:"unique_index"` CIDR string Type NetworkType Via string - Users []*DBUser `gorm:"many2many:network_users;"` + Users []*dbUserModel `gorm:"many2many:network_users;"` +} + +// Network represents a VPN related network. +type Network struct { + dbNetworkModel } // GetNetwork returns a network specified by its name. -func GetNetwork(name string) (*DBNetwork, error) { +func GetNetwork(name string) (*Network, error) { if !IsInitialized() { return nil, fmt.Errorf("you first need to create server") } @@ -98,26 +104,29 @@ func GetNetwork(name string) (*DBNetwork, error) { return nil, fmt.Errorf("validation error: `%s` can only contain letters and numbers", name) } - var network DBNetwork - db.Preload("Users").Where(&DBNetwork{Name: name}).First(&network) + var network dbNetworkModel + db.Preload("Users").Where(&dbNetworkModel{Name: name}).First(&network) if db.NewRecord(&network) { return nil, fmt.Errorf("network not found %s", name) } - return &network, nil + return &Network{dbNetworkModel: network}, nil } // GetAllNetworks returns all networks defined in the system. -func GetAllNetworks() []*DBNetwork { - var networks []*DBNetwork - db.Preload("Users").Find(&networks) - +func GetAllNetworks() []*Network { + var networks []*Network + var dbNetworks []*dbNetworkModel + db.Preload("Users").Find(&dbNetworks) + for _, n := range dbNetworks { + networks = append(networks, &Network{dbNetworkModel: *n}) + } return networks } // CreateNewNetwork creates a new network definition in the system. -func CreateNewNetwork(name, cidr string, nettype NetworkType, via string) (*DBNetwork, error) { +func CreateNewNetwork(name, cidr string, nettype NetworkType, via string) (*Network, error) { if !IsInitialized() { return nil, fmt.Errorf("you first need to create server") } @@ -158,11 +167,11 @@ func CreateNewNetwork(name, cidr string, nettype NetworkType, via string) (*DBNe via = "" } - network := DBNetwork{ + network := dbNetworkModel{ Name: name, CIDR: ipnet.String(), Type: nettype, - Users: []*DBUser{}, + Users: []*dbUserModel{}, Via: via, } db.Save(&network) @@ -172,24 +181,24 @@ func CreateNewNetwork(name, cidr string, nettype NetworkType, via string) (*DBNe } Emit() logrus.Infof("network defined: %s (%s)", network.Name, network.CIDR) - return &network, nil + return &Network{dbNetworkModel: network}, nil } // Delete deletes a network definition in the system. -func (n *DBNetwork) Delete() error { +func (n *Network) Delete() error { if !IsInitialized() { return fmt.Errorf("you first need to create server") } - db.Unscoped().Delete(n) + db.Unscoped().Delete(n.dbNetworkModel) Emit() logrus.Infof("network deleted: %s", n.Name) return nil } // Associate allows the given user access to this network. -func (n *DBNetwork) Associate(username string) error { +func (n *Network) Associate(username string) error { if !IsInitialized() { return fmt.Errorf("you first need to create server") } @@ -198,8 +207,8 @@ func (n *DBNetwork) Associate(username string) error { return fmt.Errorf("user can not be fetched: %v", err) } - var users []DBUser - userAssoc := db.Model(&n).Association("Users") + var users []dbUserModel + userAssoc := db.Model(&n.dbNetworkModel).Association("Users") userAssoc.Find(&users) var found bool for _, u := range users { @@ -212,7 +221,7 @@ func (n *DBNetwork) Associate(username string) error { return fmt.Errorf("user %s is already associated with the network %s", user.Username, n.Name) } - userAssoc.Append(user) + userAssoc.Append(user.dbUserModel) if userAssoc.Error != nil { return fmt.Errorf("association failed: %v", userAssoc.Error) } @@ -222,7 +231,7 @@ func (n *DBNetwork) Associate(username string) error { } // Dissociate breaks up the given users association to the said network. -func (n *DBNetwork) Dissociate(username string) error { +func (n *Network) Dissociate(username string) error { if !IsInitialized() { return fmt.Errorf("you first need to create server") } @@ -232,8 +241,8 @@ func (n *DBNetwork) Dissociate(username string) error { return fmt.Errorf("user can not be fetched: %v", err) } - var users []DBUser - userAssoc := db.Model(&n).Association("Users") + var users []dbUserModel + userAssoc := db.Model(&n.dbNetworkModel).Association("Users") userAssoc.Find(&users) var found bool for _, u := range users { @@ -246,7 +255,7 @@ func (n *DBNetwork) Dissociate(username string) error { return fmt.Errorf("user %s is already not associated with the network %s", user.Username, n.Name) } - userAssoc.Delete(user) + userAssoc.Delete(user.dbUserModel) if userAssoc.Error != nil { return fmt.Errorf("disassociation failed: %v", userAssoc.Error) } @@ -256,32 +265,36 @@ func (n *DBNetwork) Dissociate(username string) error { } // GetName returns network's name. -func (n *DBNetwork) GetName() string { +func (n *Network) GetName() string { return n.Name } // GetCIDR returns network's CIDR. -func (n *DBNetwork) GetCIDR() string { +func (n *Network) GetCIDR() string { return n.CIDR } // GetCreatedAt returns network's name. -func (n *DBNetwork) GetCreatedAt() string { +func (n *Network) GetCreatedAt() string { return n.CreatedAt.Format(time.UnixDate) } // GetType returns network's network type. -func (n *DBNetwork) GetType() NetworkType { +func (n *Network) GetType() NetworkType { return NetworkType(n.Type) } // GetAssociatedUsers returns network's associated users. -func (n *DBNetwork) GetAssociatedUsers() []*DBUser { - return n.Users +func (n *Network) GetAssociatedUsers() []*User { + var users []*User + for _, u := range n.Users { + users = append(users, &User{dbUserModel: *u}) + } + return users } // GetAssociatedUsernames returns network's associated user names. -func (n *DBNetwork) GetAssociatedUsernames() []string { +func (n *Network) GetAssociatedUsernames() []string { var usernames []string for _, user := range n.GetAssociatedUsers() { @@ -291,7 +304,7 @@ func (n *DBNetwork) GetAssociatedUsernames() []string { } // GetVia returns network' via. -func (n *DBNetwork) GetVia() string { +func (n *Network) GetVia() string { return n.Via } diff --git a/net_test.go b/net_test.go index e59542e..77624ea 100644 --- a/net_test.go +++ b/net_test.go @@ -7,8 +7,8 @@ import ( func TestVPNCreateNewNetwork(t *testing.T) { // Initialize: setupTestCase() - SetupDB("sqlite3", ":memory:") - defer CeaseDB() + CreateDB("sqlite3", ":memory:") + defer db.Cease() Init("localhost", "", UDPProto, "") // Prepare: @@ -30,7 +30,7 @@ func TestVPNCreateNewNetwork(t *testing.T) { t.Fatalf("network CIDR is expected to be '%s' but it's '%s' instead", cidrStr, n.CIDR) } - var network DBNetwork + var network dbNetworkModel db.First(&network) if db.NewRecord(&network) { @@ -54,8 +54,8 @@ func TestVPNCreateNewNetwork(t *testing.T) { func TestVPNDeleteNetwork(t *testing.T) { // Initialize: setupTestCase() - SetupDB("sqlite3", ":memory:") - defer CeaseDB() + CreateDB("sqlite3", ":memory:") + defer db.Cease() Init("localhost", "", UDPProto, "") // Prepare: @@ -69,7 +69,7 @@ func TestVPNDeleteNetwork(t *testing.T) { t.Fatalf("unexpected error when creating a new network: %v", err) } - var network DBNetwork + var network dbNetworkModel db.First(&network) if db.NewRecord(&network) { @@ -82,7 +82,7 @@ func TestVPNDeleteNetwork(t *testing.T) { } // Empty the existing network object. - network = DBNetwork{} + network = dbNetworkModel{} db.First(&network) if !db.NewRecord(&network) { t.Fatalf("network is not deleted from the database. %+v", network) @@ -92,8 +92,8 @@ func TestVPNDeleteNetwork(t *testing.T) { func TestVPNGetNetwork(t *testing.T) { // Initialize: setupTestCase() - SetupDB("sqlite3", ":memory:") - defer CeaseDB() + CreateDB("sqlite3", ":memory:") + defer db.Cease() Init("localhost", "", UDPProto, "") // Prepare: @@ -107,7 +107,7 @@ func TestVPNGetNetwork(t *testing.T) { t.Fatalf("unexpected error when creating a new network: %v", err) } - var network DBNetwork + var network dbNetworkModel db.First(&network) if db.NewRecord(&network) { @@ -119,7 +119,7 @@ func TestVPNGetNetwork(t *testing.T) { t.Fatalf("unexpected error: %v", err) } - if db.NewRecord(&n) { + if db.NewRecord(&n.dbNetworkModel) { t.Fatalf("network is not correctly returned from db.") } } @@ -127,8 +127,8 @@ func TestVPNGetNetwork(t *testing.T) { func TestVPNGetAllNetworks(t *testing.T) { // Initialize: setupTestCase() - SetupDB("sqlite3", ":memory:") - defer CeaseDB() + CreateDB("sqlite3", ":memory:") + defer db.Cease() Init("localhost", "", UDPProto, "") // Prepare: @@ -173,8 +173,8 @@ func TestVPNGetAllNetworks(t *testing.T) { func TestNetAssociate(t *testing.T) { // Initialize: setupTestCase() - SetupDB("sqlite3", ":memory:") - defer CeaseDB() + CreateDB("sqlite3", ":memory:") + defer db.Cease() Init("localhost", "", UDPProto, "") // Prepare: @@ -188,20 +188,27 @@ func TestNetAssociate(t *testing.T) { t.Fatal(err) } - n, _ := CreateNewNetwork(netName, cidrStr, netType, "") - err = n.Associate(user.Username) + n, err := CreateNewNetwork(netName, cidrStr, netType, "") + if err != nil { + t.Fatal(err) + } + + err = n.Associate(user.dbUserModel.Username) if err != nil { t.Fatal(err) } n = nil - n, _ = GetNetwork(netName) + n, err = GetNetwork(netName) + if err != nil { + t.Fatal(err) + } // Does number of associated users in the network object matches the number that we have created? - if count := len(n.Users); count != 1 { + if count := len(n.dbNetworkModel.Users); count != 1 { t.Fatalf("network.Users count is expexted to be %d, but it's %d", 1, count) } - err = n.Associate(user.Username) + err = n.Associate(user.dbUserModel.Username) if err == nil { t.Fatalf("expected to get error but got no error instead") } @@ -211,8 +218,8 @@ func TestNetAssociate(t *testing.T) { func TestNetDissociate(t *testing.T) { // Initialize: setupTestCase() - SetupDB("sqlite3", ":memory:") - defer CeaseDB() + CreateDB("sqlite3", ":memory:") + defer db.Cease() err := Init("localhost", "", UDPProto, "") if err != nil { t.Fatal(err) @@ -264,8 +271,8 @@ func TestNetDissociate(t *testing.T) { func TestNetGetAssociatedUsers(t *testing.T) { // Initialize: setupTestCase() - SetupDB("sqlite3", ":memory:") - defer CeaseDB() + CreateDB("sqlite3", ":memory:") + defer db.Cease() Init("localhost", "", UDPProto, "") // Prepare: diff --git a/user.go b/user.go index 501235f..bb85ce8 100644 --- a/user.go +++ b/user.go @@ -13,22 +13,17 @@ import ( "github.com/jinzhu/gorm" ) -// User represents the interface that is being used within the public api. -type User interface { - GetUsername() string - GetServerSerialNumber() string - GetCert() string - GetIPNet() string - IsNoGW() bool - GetHostID() uint32 - IsAdmin() bool +// dbRevokedModel is a database model for revoked VPN users. +type dbRevokedModel struct { + gorm.Model + SerialNumber string } -// DBUser is database model for VPN users. -type DBUser struct { +// dbUserModel is database model for VPN users. +type dbUserModel struct { gorm.Model ServerID uint - Server DBServer + Server dbServerModel Username string `gorm:"unique_index"` Cert string // not user writable @@ -40,13 +35,12 @@ type DBUser struct { Admin bool } -// DBRevoked is a database model for revoked VPN users. -type DBRevoked struct { - gorm.Model - SerialNumber string +// User represents a vpn user. +type User struct { + dbUserModel } -func (u *DBUser) setPassword(password string) error { +func (u *dbUserModel) setPassword(password string) error { hashedPassword, err := passlib.Hash(password) if err != nil { return fmt.Errorf("can not set password: %v", err) @@ -57,7 +51,7 @@ func (u *DBUser) setPassword(password string) error { } // CheckPassword returns whether the given password is correct for the user. -func (u *DBUser) CheckPassword(password string) bool { +func (u *User) CheckPassword(password string) bool { _, err := passlib.Verify(password, u.Hash) if err != nil { logrus.Error(err) @@ -67,21 +61,24 @@ func (u *DBUser) CheckPassword(password string) bool { } // GetUser finds and returns the user with the given username from database. -func GetUser(username string) (*DBUser, error) { - user := DBUser{} - db.Where(&DBUser{Username: username}).First(&user) +func GetUser(username string) (*User, error) { + user := dbUserModel{} + db.Where(&dbUserModel{Username: username}).First(&user) if db.NewRecord(&user) { // user is not found return nil, fmt.Errorf("user not found: %s", username) } - return &user, nil + return &User{dbUserModel: user}, nil } // GetAllUsers returns all recorded users in the database. -func GetAllUsers() ([]*DBUser, error) { - var users []*DBUser - db.Find(&users) - +func GetAllUsers() ([]*User, error) { + var users []*User + var dbUsers []*dbUserModel + db.Find(&dbUsers) + for _, u := range dbUsers { + users = append(users, &User{dbUserModel: *u}) + } return users, nil } @@ -91,7 +88,7 @@ func GetAllUsers() ([]*DBUser, error) { // // It also generates the necessary client keys and signs certificates with the current // server's CA. -func CreateNewUser(username, password string, nogw bool, hostid uint32, admin bool) (*DBUser, error) { +func CreateNewUser(username, password string, nogw bool, hostid uint32, admin bool) (*User, error) { if !IsInitialized() { return nil, fmt.Errorf("you first need to create server") } @@ -132,7 +129,7 @@ func CreateNewUser(username, password string, nogw bool, hostid uint32, admin bo return nil, fmt.Errorf("ip %s is already allocated", ip) } } - user := DBUser{ + user := dbUserModel{ Username: username, Cert: clientCert.Cert, Key: clientCert.Key, @@ -155,13 +152,13 @@ func CreateNewUser(username, password string, nogw bool, hostid uint32, admin bo if err != nil { return nil, err } - return &user, nil + return &User{dbUserModel: user}, nil } // Update updates the user's attributes and writes them to the database. // // How this method works is similiar to PUT semantics of REST. It sets the user record fields to the provided function arguments. -func (u *DBUser) Update(password string, nogw bool, hostid uint32, admin bool) error { +func (u *User) Update(password string, nogw bool, hostid uint32, admin bool) error { if !IsInitialized() { return fmt.Errorf("you first need to create server") } @@ -195,7 +192,7 @@ func (u *DBUser) Update(password string, nogw bool, hostid uint32, admin bool) e return fmt.Errorf("ip %s is already allocated", ip) } } - db.Save(u) + db.Save(u.dbUserModel) err := Emit() if err != nil { @@ -205,8 +202,8 @@ func (u *DBUser) Update(password string, nogw bool, hostid uint32, admin bool) e } // Delete deletes a user by the given username from the database. -func (u *DBUser) Delete() error { - if db.NewRecord(u) { +func (u *User) Delete() error { + if db.NewRecord(u.dbUserModel) { // user is not found return fmt.Errorf("user is not initialized: %s", u.Username) } @@ -214,10 +211,10 @@ func (u *DBUser) Delete() error { if err != nil { return fmt.Errorf("can not get user's certificate: %v", err) } - db.Create(&DBRevoked{ + db.Create(&dbRevokedModel{ SerialNumber: crt.SerialNumber.Text(16), }) - db.Unscoped().Delete(u) + db.Unscoped().Delete(u.dbUserModel) logrus.Infof("user deleted: %s", u.GetUsername()) err = Emit() if err != nil { @@ -228,13 +225,13 @@ func (u *DBUser) Delete() error { } // ResetPassword resets the users password into the provided password. -func (u *DBUser) ResetPassword(password string) error { - err := u.setPassword(password) +func (u *User) ResetPassword(password string) error { + err := u.dbUserModel.setPassword(password) if err != nil { // user password can not be updated return fmt.Errorf("user password can not be updated %s: %v", u.Username, err) } - db.Save(u) + db.Save(u.dbUserModel) err = Emit() if err != nil { return err @@ -250,7 +247,7 @@ func (u *DBUser) ResetPassword(password string) error { // still existing users in the database. // // Also it can be used when a user cert is expired or user's private key stolen, missing etc. -func (u *DBUser) Renew() error { +func (u *User) Renew() error { if !IsInitialized() { return fmt.Errorf("you first need to create server") } @@ -273,7 +270,7 @@ func (u *DBUser) Renew() error { u.Key = clientCert.Key u.ServerSerialNumber = server.SerialNumber - db.Save(u) + db.Save(u.dbUserModel) err = Emit() if err != nil { return err @@ -284,27 +281,27 @@ func (u *DBUser) Renew() error { } // GetUsername returns user's username. -func (u *DBUser) GetUsername() string { +func (u *User) GetUsername() string { return u.Username } // GetCert returns user's public certificate. -func (u *DBUser) GetCert() string { +func (u *User) GetCert() string { return u.Cert } // GetServerSerialNumber returns user's server serial number. -func (u *DBUser) GetServerSerialNumber() string { +func (u *User) GetServerSerialNumber() string { return u.ServerSerialNumber } // GetCreatedAt returns user's creation time. -func (u *DBUser) GetCreatedAt() string { +func (u *User) GetCreatedAt() string { return u.CreatedAt.Format(time.UnixDate) } // getIP returns user's vpn ip addr. -func (u *DBUser) getIP() net.IP { +func (u *User) getIP() net.IP { users := getNonStaticHostUsers() staticHostIDs := getStaticHostIDs() server, err := GetServerInstance() @@ -342,7 +339,7 @@ func (u *DBUser) getIP() net.IP { } // GetIPNet returns user's vpn ip network. (e.g. 192.168.0.1/24) -func (u *DBUser) GetIPNet() string { +func (u *User) GetIPNet() string { server, err := GetServerInstance() if err != nil { logrus.Panicf("can not get user ipnet: %v", err) @@ -357,29 +354,42 @@ func (u *DBUser) GetIPNet() string { } // IsNoGW returns whether user is set to get the vpn server as their default gateway. -func (u *DBUser) IsNoGW() bool { +func (u *User) IsNoGW() bool { return u.NoGW } // GetHostID returns user's Host ID. -func (u *DBUser) GetHostID() uint32 { +func (u *User) GetHostID() uint32 { return u.HostID } // IsAdmin returns whether user is admin or not. -func (u *DBUser) IsAdmin() bool { +func (u *User) IsAdmin() bool { return u.Admin } -func getStaticHostUsers() []*DBUser { - var users []*DBUser - db.Unscoped().Not(DBUser{HostID: 0}).Find(&users) +func (u *User) getKey() string { + return u.Key +} + +func getStaticHostUsers() []*User { + var users []*User + var dbUsers []*dbUserModel + db.Unscoped().Not(dbUserModel{HostID: 0}).Find(&dbUsers) + for _, u := range dbUsers { + users = append(users, &User{dbUserModel: *u}) + } return users } -func getNonStaticHostUsers() []*DBUser { - var users []*DBUser - db.Unscoped().Where(DBUser{HostID: 0}).Find(&users) +func getNonStaticHostUsers() []*User { + var users []*User + var dbUsers []*dbUserModel + db.Unscoped().Where(dbUserModel{HostID: 0}).Find(&dbUsers) + for _, u := range dbUsers { + users = append(users, &User{dbUserModel: *u}) + } + return users } diff --git a/user_test.go b/user_test.go index d4a4929..fcfe504 100644 --- a/user_test.go +++ b/user_test.go @@ -11,8 +11,8 @@ import ( func TestCreateNewUser(t *testing.T) { // Initialize: - ovpm.SetupDB("sqlite3", ":memory:") - defer ovpm.CeaseDB() + db := ovpm.CreateDB("sqlite3", ":memory:") + defer db.Cease() ovpm.Init("localhost", "", ovpm.UDPProto, "") server, _ := ovpm.GetServerInstance() @@ -32,11 +32,6 @@ func TestCreateNewUser(t *testing.T) { t.Fatalf("user is expected to be 'NOT nil' but it is 'nil' %+v", user) } - // Is user empty? - if *user == (ovpm.DBUser{}) { - t.Fatalf("user is expected to be 'NOT EMPTY' but it is 'EMPTY' %+v", user) - } - // Is user acutally exist in the system? user2, err := ovpm.GetUser(username) if err != nil { @@ -87,8 +82,8 @@ func TestCreateNewUser(t *testing.T) { func TestUserUpdate(t *testing.T) { // Initialize: - ovpm.SetupDB("sqlite3", ":memory:") - defer ovpm.CeaseDB() + db := ovpm.CreateDB("sqlite3", ":memory:") + defer db.Cease() ovpm.Init("localhost", "", ovpm.UDPProto, "") // Prepare: @@ -125,8 +120,8 @@ func TestUserUpdate(t *testing.T) { func TestUserPasswordCorrect(t *testing.T) { // Initialize: - ovpm.SetupDB("sqlite3", ":memory:") - defer ovpm.CeaseDB() + db := ovpm.CreateDB("sqlite3", ":memory:") + defer db.Cease() ovpm.Init("localhost", "", ovpm.UDPProto, "") // Prepare: @@ -142,8 +137,8 @@ func TestUserPasswordCorrect(t *testing.T) { func TestUserPasswordReset(t *testing.T) { // Initialize: - ovpm.SetupDB("sqlite3", ":memory:") - defer ovpm.CeaseDB() + db := ovpm.CreateDB("sqlite3", ":memory:") + defer db.Cease() ovpm.Init("localhost", "", ovpm.UDPProto, "") // Prepare: @@ -169,8 +164,8 @@ func TestUserPasswordReset(t *testing.T) { func TestUserDelete(t *testing.T) { // Initialize: - ovpm.SetupDB("sqlite3", ":memory:") - defer ovpm.CeaseDB() + db := ovpm.CreateDB("sqlite3", ":memory:") + defer db.Cease() ovpm.Init("localhost", "", ovpm.UDPProto, "") // Prepare: @@ -207,8 +202,8 @@ func TestUserDelete(t *testing.T) { func TestUserGet(t *testing.T) { // Initialize: - ovpm.SetupDB("sqlite3", ":memory:") - defer ovpm.CeaseDB() + db := ovpm.CreateDB("sqlite3", ":memory:") + defer db.Cease() ovpm.Init("localhost", "", ovpm.UDPProto, "") // Prepare: @@ -231,13 +226,13 @@ func TestUserGet(t *testing.T) { func TestUserGetAll(t *testing.T) { // Initialize: - ovpm.SetupDB("sqlite3", ":memory:") - defer ovpm.CeaseDB() + db := ovpm.CreateDB("sqlite3", ":memory:") + defer db.Cease() ovpm.Init("localhost", "", ovpm.UDPProto, "") count := 5 // Prepare: - var users []*ovpm.DBUser + var users []*ovpm.User for i := 0; i < count; i++ { username := fmt.Sprintf("user%d", i) password := fmt.Sprintf("password%d", i) @@ -269,8 +264,8 @@ func TestUserGetAll(t *testing.T) { func TestUserRenew(t *testing.T) { // Initialize: - ovpm.SetupDB("sqlite3", ":memory:") - defer ovpm.CeaseDB() + db := ovpm.CreateDB("sqlite3", ":memory:") + defer db.Cease() ovpm.Init("localhost", "", ovpm.UDPProto, "") // Prepare: @@ -291,8 +286,8 @@ func TestUserRenew(t *testing.T) { func TestUserIPAllocator(t *testing.T) { // Initialize: - ovpm.SetupDB("sqlite3", ":memory:") - defer ovpm.CeaseDB() + db := ovpm.CreateDB("sqlite3", ":memory:") + defer db.Cease() ovpm.Init("localhost", "", ovpm.UDPProto, "") // Prepare: @@ -326,21 +321,18 @@ func TestUserIPAllocator(t *testing.T) { } // areUsersEqual compares given users and returns true if they are the same. -func areUsersEqual(user1, user2 *ovpm.DBUser) bool { - if user1.Cert != user2.Cert { - logrus.Info("Cert %v != %v", user1.Cert, user2.Cert) +func areUsersEqual(user1, user2 *ovpm.User) bool { + if user1.GetCert() != user2.GetCert() { + logrus.Info("Cert %v != %v", user1.GetCert(), user2.GetCert()) return false } - if user1.Username != user2.Username { - logrus.Infof("Username %v != %v", user1.Username, user2.Username) + if user1.GetUsername() != user2.GetUsername() { + logrus.Infof("Username %v != %v", user1.GetUsername(), user2.GetUsername()) return false } - if user1.Hash != user2.Hash { - logrus.Infof("Password %v != %v", user1.Hash, user2.Hash) - return false - } - if user1.ServerSerialNumber != user2.ServerSerialNumber { - logrus.Infof("ServerSerialNumber %v != %v", user1.ServerSerialNumber, user2.ServerSerialNumber) + + if user1.GetServerSerialNumber() != user2.GetServerSerialNumber() { + logrus.Infof("ServerSerialNumber %v != %v", user1.GetServerSerialNumber(), user2.GetServerSerialNumber()) return false } logrus.Infof("users are the same!") diff --git a/vpn.go b/vpn.go index b4db7b3..e46ef59 100644 --- a/vpn.go +++ b/vpn.go @@ -3,6 +3,9 @@ //go:generate protoc -I pb/ -I$GOPATH/src/github.com/grpc-ecosystem/grpc-gateway/third_party/googleapis pb/user.proto pb/vpn.proto pb/network.proto --grpc-gateway_out=logtostderr=true:pb //go:generate protoc -I pb/ -I$GOPATH/src/github.com/grpc-ecosystem/grpc-gateway/third_party/googleapis pb/user.proto pb/vpn.proto pb/network.proto --swagger_out=logtostderr=true:pb +// Package ovpm provides the implementation of core API. +// +// ovpm can create and destroy OpenVPN servers, manage vpn users, handle certificates etc... package ovpm import ( @@ -33,8 +36,8 @@ const ( UDPProto string = "udp" ) -// DBServer is database model for storing VPN server related stuff. -type DBServer struct { +// serverModel is database model for storing VPN server related stuff. +type dbServerModel struct { gorm.Model Name string `gorm:"unique_index"` // Server name. SerialNumber string @@ -51,11 +54,91 @@ type DBServer struct { CRL string // Certificate Revocation List } +// Server represents VPN server. +type Server struct { + dbServerModel +} + // CheckSerial takes a serial number and checks it against the current server's serial number. -func (s *DBServer) CheckSerial(serial string) bool { +func (s *Server) CheckSerial(serial string) bool { return serial == s.SerialNumber } +// GetSerialNumber returns server's serial number. +func (s *Server) GetSerialNumber() string { + return s.SerialNumber +} + +// GetServerName returns server's name. +func (s *Server) GetServerName() string { + if s.Name != "" { + return s.Name + } + return "default" +} + +// GetHostname returns vpn server's hostname. +func (s *Server) GetHostname() string { + return s.Hostname +} + +// GetPort returns vpn server's port. +func (s *Server) GetPort() string { + if s.Port != "" { + return s.Port + } + return DefaultVPNPort + +} + +// GetProto returns vpn server's proto. +func (s *Server) GetProto() string { + if s.Proto != "" { + return s.Proto + } + return DefaultVPNProto +} + +// GetCert returns vpn server's cert. +func (s *Server) GetCert() string { + return s.Cert +} + +// GetKey returns vpn server's key. +func (s *Server) GetKey() string { + return s.Key +} + +// GetCACert returns vpn server's cacert. +func (s *Server) GetCACert() string { + return s.CACert +} + +// GetCAKey returns vpn server's cakey. +func (s *Server) GetCAKey() string { + return s.CAKey +} + +// GetNet returns vpn server's net. +func (s *Server) GetNet() string { + return s.Net +} + +// GetMask returns vpn server's mask. +func (s *Server) GetMask() string { + return s.Mask +} + +// GetCRL returns vpn server's crl. +func (s *Server) GetCRL() string { + return s.CRL +} + +// GetCreatedAt returns server's created at. +func (s *Server) GetCreatedAt() string { + return s.CreatedAt.Format(time.UnixDate) +} + type _VPNServerConfig struct { CertPath string KeyPath string @@ -150,7 +233,7 @@ func Init(hostname string, port string, proto string, ipblock string) error { } serialNumber := uuid.New().String() - serverInstance := DBServer{ + serverInstance := dbServerModel{ Name: serverName, SerialNumber: serialNumber, @@ -189,14 +272,14 @@ func Init(hostname string, port string, proto string, ipblock string) error { return nil } -// Deinit deletes the server with the given serverName from the database and frees the allocated resources. +// Deinit deletes the VPN server from the database and frees the allocated resources. func Deinit() error { if !IsInitialized() { return fmt.Errorf("server not found") } - db.Unscoped().Delete(&DBServer{}) - db.Unscoped().Delete(&DBRevoked{}) + db.Unscoped().Delete(&dbServerModel{}) + db.Unscoped().Delete(&dbRevokedModel{}) Emit() return nil } @@ -223,12 +306,12 @@ func DumpsClientConfig(username string) (string, error) { NoGW bool Proto string }{ - Hostname: server.Hostname, - Port: server.Port, - CA: server.CACert, - Key: user.Key, - Cert: user.Cert, - NoGW: user.NoGW, + Hostname: server.GetHostname(), + Port: server.GetPort(), + CA: server.GetCACert(), + Key: user.getKey(), + Cert: user.GetCert(), + NoGW: user.IsNoGW(), Proto: server.GetProto(), } data, err := bindata.Asset("template/client.ovpn.tmpl") @@ -262,7 +345,7 @@ func DumpClientConfig(username, path string) error { // GetSystemCA returns the system CA from the database if available. func GetSystemCA() (*pki.CA, error) { - server := DBServer{} + server := dbServerModel{} db.First(&server) if db.NewRecord(&server) { return nil, fmt.Errorf("server record does not exists in db") @@ -467,26 +550,18 @@ func emitServerConf() error { } // GetServerInstance returns the default server from the database. -func GetServerInstance() (*DBServer, error) { - var server DBServer +func GetServerInstance() (*Server, error) { + var server dbServerModel db.First(&server) if db.NewRecord(server) { return nil, fmt.Errorf("can not retrieve server from db") } - return &server, nil -} - -// GetProto returns the current VPN proto. -func (s *DBServer) GetProto() string { - if s.Proto != "" { - return s.Proto - } - return UDPProto + return &Server{dbServerModel: server}, nil } -// IsInitialized checks if there is a default server in the database or not. +// IsInitialized checks if there is a default VPN server configured in the database or not. func IsInitialized() bool { - var server DBServer + var server dbServerModel db.First(&server) if db.NewRecord(server) { return false @@ -515,7 +590,7 @@ func emitServerCert() error { } func emitCRL() error { - var revokedDBItems []*DBRevoked + var revokedDBItems []*dbRevokedModel db.Find(&revokedDBItems) var revokedCertSerials []*big.Int for _, item := range revokedDBItems { diff --git a/vpn_test.go b/vpn_test.go index 66b3b09..a5f7c1b 100644 --- a/vpn_test.go +++ b/vpn_test.go @@ -20,13 +20,13 @@ func setupTestCase() { func TestVPNInit(t *testing.T) { // Init: setupTestCase() - SetupDB("sqlite3", ":memory:") - defer CeaseDB() + CreateDB("sqlite3", ":memory:") + defer db.Cease() // Prepare: // Test: // Check database if the database has no server. - var server DBServer + var server dbServerModel db.First(&server) // Isn't server empty struct? @@ -44,7 +44,7 @@ func TestVPNInit(t *testing.T) { Init("localhost", "", UDPProto, "") // Check database if the database has no server. - var server2 DBServer + var server2 dbServerModel db.First(&server2) // Is server empty struct? @@ -56,8 +56,8 @@ func TestVPNInit(t *testing.T) { func TestVPNDeinit(t *testing.T) { // Init: setupTestCase() - SetupDB("sqlite3", ":memory:") - defer CeaseDB() + CreateDB("sqlite3", ":memory:") + defer db.Cease() // Prepare: // Initialize the server. @@ -69,7 +69,7 @@ func TestVPNDeinit(t *testing.T) { u.Delete() // Test: - var server DBServer + var server dbServerModel db.First(&server) // Isn't server empty struct? @@ -78,7 +78,7 @@ func TestVPNDeinit(t *testing.T) { } // Test if Revoked table contains the removed user's entries. - var revoked DBRevoked + var revoked dbRevokedModel db.First(&revoked) if db.NewRecord(&revoked) { @@ -89,7 +89,7 @@ func TestVPNDeinit(t *testing.T) { Deinit() // Get server from db. - var server2 DBServer + var server2 dbServerModel db.First(&server2) // Isn't server empty struct? @@ -98,7 +98,7 @@ func TestVPNDeinit(t *testing.T) { } // Test if Revoked table contains the removed user's entries. - var revoked2 DBRevoked + var revoked2 dbRevokedModel db.First(&revoked2) // Is revoked empty? @@ -110,8 +110,8 @@ func TestVPNDeinit(t *testing.T) { func TestVPNIsInitialized(t *testing.T) { // Init: setupTestCase() - SetupDB("sqlite3", ":memory:") - defer CeaseDB() + CreateDB("sqlite3", ":memory:") + defer db.Cease() // Prepare: @@ -133,8 +133,8 @@ func TestVPNIsInitialized(t *testing.T) { func TestVPNGetServerInstance(t *testing.T) { // Init: setupTestCase() - SetupDB("sqlite3", ":memory:") - defer CeaseDB() + CreateDB("sqlite3", ":memory:") + defer db.Cease() // Prepare: @@ -170,8 +170,8 @@ func TestVPNGetServerInstance(t *testing.T) { func TestVPNDumpsClientConfig(t *testing.T) { // Init: setupTestCase() - SetupDB("sqlite3", ":memory:") - defer CeaseDB() + CreateDB("sqlite3", ":memory:") + defer db.Cease() Init("localhost", "", UDPProto, "") // Prepare: @@ -192,8 +192,8 @@ func TestVPNDumpsClientConfig(t *testing.T) { func TestVPNDumpClientConfig(t *testing.T) { // Init: setupTestCase() - SetupDB("sqlite3", ":memory:") - defer CeaseDB() + CreateDB("sqlite3", ":memory:") + defer db.Cease() Init("localhost", "", UDPProto, "") // Prepare: @@ -250,8 +250,8 @@ func TestVPNDumpClientConfig(t *testing.T) { func TestVPNGetSystemCA(t *testing.T) { // Init: setupTestCase() - SetupDB("sqlite3", ":memory:") - defer CeaseDB() + CreateDB("sqlite3", ":memory:") + defer db.Cease() // Prepare: @@ -282,8 +282,8 @@ func TestVPNGetSystemCA(t *testing.T) { func TestVPNStartVPNProc(t *testing.T) { // Init: setupTestCase() - SetupDB("sqlite3", ":memory:") - defer CeaseDB() + CreateDB("sqlite3", ":memory:") + defer db.Cease() // Prepare: @@ -316,8 +316,8 @@ func TestVPNStartVPNProc(t *testing.T) { func TestVPNStopVPNProc(t *testing.T) { // Init: setupTestCase() - SetupDB("sqlite3", ":memory:") - defer CeaseDB() + CreateDB("sqlite3", ":memory:") + defer db.Cease() Init("localhost", "", UDPProto, "") // Prepare: @@ -340,8 +340,8 @@ func TestVPNStopVPNProc(t *testing.T) { func TestVPNRestartVPNProc(t *testing.T) { // Init: - SetupDB("sqlite3", ":memory:") - defer CeaseDB() + CreateDB("sqlite3", ":memory:") + defer db.Cease() Init("localhost", "", UDPProto, "") // Prepare: @@ -369,8 +369,8 @@ func TestVPNRestartVPNProc(t *testing.T) { func TestVPNEmit(t *testing.T) { // Init: setupTestCase() - SetupDB("sqlite3", ":memory:") - defer CeaseDB() + CreateDB("sqlite3", ":memory:") + defer db.Cease() Init("localhost", "", UDPProto, "") // Prepare: From 2bfcfe801c2f528a2a5e4a458d82955e4adae00a Mon Sep 17 00:00:00 2001 From: Mustafa Arici Date: Sat, 2 Sep 2017 11:13:27 +0300 Subject: [PATCH 02/10] doc: clarify which api --- vpn.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vpn.go b/vpn.go index e46ef59..d3c9b3a 100644 --- a/vpn.go +++ b/vpn.go @@ -3,7 +3,7 @@ //go:generate protoc -I pb/ -I$GOPATH/src/github.com/grpc-ecosystem/grpc-gateway/third_party/googleapis pb/user.proto pb/vpn.proto pb/network.proto --grpc-gateway_out=logtostderr=true:pb //go:generate protoc -I pb/ -I$GOPATH/src/github.com/grpc-ecosystem/grpc-gateway/third_party/googleapis pb/user.proto pb/vpn.proto pb/network.proto --swagger_out=logtostderr=true:pb -// Package ovpm provides the implementation of core API. +// Package ovpm provides the implementation of core OVPM API. // // ovpm can create and destroy OpenVPN servers, manage vpn users, handle certificates etc... package ovpm From a83447d466393b4724db3e173f2303077c699043 Mon Sep 17 00:00:00 2001 From: Mustafa Arici Date: Sat, 2 Sep 2017 11:20:47 +0300 Subject: [PATCH 03/10] fix(cli): don't forget to apply changes to ovpmd cmd --- cmd/ovpmd/main.go | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/cmd/ovpmd/main.go b/cmd/ovpmd/main.go index 22956ad..9763a19 100644 --- a/cmd/ovpmd/main.go +++ b/cmd/ovpmd/main.go @@ -24,6 +24,7 @@ import ( ) var action string +var db *ovpm.DB func main() { app := cli.NewApp() @@ -45,11 +46,11 @@ func main() { if c.GlobalBool("verbose") { logrus.SetLevel(logrus.DebugLevel) } - ovpm.SetupDB("sqlite3", "") + db = ovpm.CreateDB("sqlite3", "") return nil } app.After = func(c *cli.Context) error { - ovpm.CeaseDB() + db.Cease() return nil } app.Action = func(c *cli.Context) error { From 1de0a48fe853a9aba105a537528b0fd1336d4629 Mon Sep 17 00:00:00 2001 From: Mustafa Arici Date: Sat, 2 Sep 2017 11:38:52 +0300 Subject: [PATCH 04/10] doc(readme): add roadmap --- README.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/README.md b/README.md index e67bc87..260a3e4 100644 --- a/README.md +++ b/README.md @@ -11,6 +11,16 @@ With OVPM you can create and run an OpenVPN server, add/remove VPN users, genera *This software is not stable yet. We recommend against using it for anything serious until, version 1.0 is released.* +**Roadmap** + +- [x] OpenVPN management functionality +- [x] User management functionality +- [x] Network management functionality +- [x] Command Line Interface (CLI) +- [ ] Web User Interface (WebUI) +- [ ] Import/Export/Backup OVPM config +- [ ] Effortless client profile (.ovpn file) delivery over Web + ## Installation **from RPM (CentOS/Fedora):** From ac48edf20d90fb67d98e4dcb226460c0c6025dc3 Mon Sep 17 00:00:00 2001 From: Mustafa Arici Date: Sat, 2 Sep 2017 13:25:15 +0300 Subject: [PATCH 05/10] doc(readme): add asciinema demo --- README.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/README.md b/README.md index 260a3e4..4f36b78 100644 --- a/README.md +++ b/README.md @@ -81,6 +81,12 @@ It complains about an error due to server not being initialized, it's completely ## Usage +**Demo** +Here is a little demo of what it looks on terminal to init the server, create a vpn user and generate **.ovpn** file for the created user. + +[![asciicast](https://asciinema.org/a/136016.png)](https://asciinema.org/a/136016) + + ### Init Server If you just installed the ovpm from scratch you have started the **ovpm server** (ovpmd) then now you need to initialize the server. From 9a5dc2aeb42e52090c0e0a9f127b873bbb288465 Mon Sep 17 00:00:00 2001 From: Mustafa Arici Date: Sat, 2 Sep 2017 14:39:58 +0300 Subject: [PATCH 06/10] chore(ci): afterupgrade script --- build.sh | 4 ++-- contrib/afterupgrade.sh | 4 ++++ 2 files changed, 6 insertions(+), 2 deletions(-) create mode 100644 contrib/afterupgrade.sh diff --git a/build.sh b/build.sh index 5ddb110..1a04ef0 100755 --- a/build.sh +++ b/build.sh @@ -41,9 +41,9 @@ cp $DIR/contrib/yumrepo.repo $RELEASEDIR/rpm/ovpm.repo cp $DIR/contrib/deb-repo-config $RELEASEDIR/deb/conf/distributions #package -fpm -s dir -t rpm -n ovpm --version `git name-rev --tags --name-only $(git rev-parse HEAD) | cut -d 'v' -f 2` --iteration $RELEASEVER --depends openvpn --description "OVPM makes all aspects of OpenVPN server administration a breeze." --after-install $DIR/contrib/afterinstall.sh --before-remove $DIR/contrib/beforeremove.sh -p $RELEASEDIR/rpm -C $RELEASEDIR/build . +fpm -s dir -t rpm -n ovpm --version `git name-rev --tags --name-only $(git rev-parse HEAD) | cut -d 'v' -f 2` --iteration $RELEASEVER --depends openvpn --description "OVPM makes all aspects of OpenVPN server administration a breeze." --after-install $DIR/contrib/afterinstall.sh --before-remove $DIR/contrib/beforeremove.sh --after-upgrade $DIR/contrib/afterupgrade.sh -p $RELEASEDIR/rpm -C $RELEASEDIR/build . -fpm -s dir -t deb -n ovpm --version `git name-rev --tags --name-only $(git rev-parse HEAD) | cut -d 'v' -f 2` --iteration $RELEASEVER --depends openvpn --description "OVPM makes all aspects of OpenVPN server administration a breeze." --after-install $DIR/contrib/afterinstall.sh --before-remove $DIR/contrib/beforeremove.sh -p $RELEASEDIR/deb -C $RELEASEDIR/build . +fpm -s dir -t deb -n ovpm --version `git name-rev --tags --name-only $(git rev-parse HEAD) | cut -d 'v' -f 2` --iteration $RELEASEVER --depends openvpn --description "OVPM makes all aspects of OpenVPN server administration a breeze." --after-install $DIR/contrib/afterinstall.sh --before-remove $DIR/contrib/beforeremove.sh --after-upgrade $DIR/contrib/afterupgrade.sh -p $RELEASEDIR/deb -C $RELEASEDIR/build . #create rpm repo createrepo --database $RELEASEDIR/rpm diff --git a/contrib/afterupgrade.sh b/contrib/afterupgrade.sh new file mode 100644 index 0000000..46b4487 --- /dev/null +++ b/contrib/afterupgrade.sh @@ -0,0 +1,4 @@ +if [ "`systemctl is-active ovpmd`" != "active" ] +then + systemctl restart ovpmd +fi From 8bbbb274018078aef3b456d2531ce86d153458c9 Mon Sep 17 00:00:00 2001 From: Mustafa Arici Date: Sun, 3 Sep 2017 13:59:24 +0300 Subject: [PATCH 07/10] feat(vpn): implement configurable dns option --- api/rpc.go | 3 +- bindata/bindata.go | 6 ++-- cmd/ovpm/vpn.go | 15 +++++++- const.go | 3 ++ net_test.go | 14 ++++---- pb/vpn.pb.go | 73 ++++++++++++++++++++++++--------------- pb/vpn.proto | 2 ++ pb/vpn.swagger.json | 6 ++++ template/server.conf.tmpl | 2 +- user_test.go | 20 +++++------ vpn.go | 55 ++++++++++++++++++++--------- vpn_test.go | 24 ++++++------- 12 files changed, 144 insertions(+), 79 deletions(-) diff --git a/api/rpc.go b/api/rpc.go index c5c5f3f..7f29702 100644 --- a/api/rpc.go +++ b/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 diff --git a/bindata/bindata.go b/bindata/bindata.go index 5c4f483..090a5dc 100644 --- a/bindata/bindata.go +++ b/bindata/bindata.go @@ -107,7 +107,7 @@ func templateClientOvpnTmpl() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "template/client.ovpn.tmpl", size: 364, mode: os.FileMode(420), modTime: time.Unix(1504303338, 0)} + info := bindataFileInfo{name: "template/client.ovpn.tmpl", size: 364, mode: os.FileMode(420), modTime: time.Unix(1504303885, 0)} a := &asset{bytes: bytes, info: info} return a, nil } @@ -152,7 +152,7 @@ func templateIptablesTmpl() (*asset, error) { return a, nil } -var _templateServerConfTmpl = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x94\x7a\x6d\x6f\xdb\xb8\xb2\xff\x7b\x7d\x8a\x81\xfd\xa2\x09\x60\x2b\x8e\xdb\xee\x69\x37\xff\xff\xbd\xf0\x3a\xee\xd6\xd8\xd6\xf5\x6d\x9c\x7d\x00\xf6\x0d\x2d\x8d\x2d\xc2\x12\xa9\x25\x29\xbb\x3e\x07\xe7\xbb\x5f\xcc\x90\x94\xe4\x24\xdd\x8b\xb3\x8b\xa0\xb6\x44\x0e\xe7\x79\x7e\x33\xf4\x5d\xad\x8d\x83\xdb\xdb\xf7\x6f\x12\xfe\xf4\xaf\x7f\x41\xba\xa6\x0f\xff\xfe\x77\x92\x0c\x61\x33\x5f\x83\x36\xf0\x78\xbf\x06\x8b\xe6\x88\xe6\xbf\x93\xbb\xda\x68\xa7\xc1\x65\x75\xe2\x3f\xf1\x16\xfe\xe4\xf7\x0c\x72\x3c\x82\x6b\xd4\x00\x4e\xb2\x2c\x21\x33\x28\x1c\x82\x00\xa3\x1b\x87\x39\x2c\xd7\xf4\x52\x61\x39\x6a\xd7\x8a\xfa\xc9\x5a\x05\xe8\x0a\x34\x0a\x5d\x58\x9b\x26\x43\x78\xb4\xd8\xae\x9f\x0c\x40\xee\xe0\xac\x1b\x10\x06\xbb\xc5\x5b\x23\xf3\xbd\x54\xfb\x64\x08\x42\xe5\x50\x88\x23\x42\x6d\xd0\x93\xcd\x41\xf0\x56\x38\x4a\xe3\x1a\x51\x82\x54\x0e\xcd\x4e\x64\x18\x96\xf3\x6e\xcc\x41\x3a\x38\x49\x57\x10\x79\xd3\xd1\x6e\x57\x13\x2f\x4b\x7f\xf8\x49\x28\x07\x4e\x43\xa6\x95\x33\xba\x04\x91\x65\x68\x2d\xd4\xba\x94\x99\x44\x9b\x0c\x41\x1f\xd1\x80\x2b\x10\x7e\x5d\xaf\x46\xbc\xa7\x6a\xac\x8b\x82\xee\xa4\xc1\x93\x28\xcb\x64\x08\xa6\x29\xd1\xc2\x4e\xfb\xd5\xf4\xb7\x79\x5c\xdd\x6c\x66\xeb\xcb\x83\xbf\x28\x50\x5a\x8d\x7f\x93\x2a\xd7\x27\x0b\xf6\x6c\x1d\x56\xd6\x53\xce\x84\x82\xbd\x3c\x7a\x71\x00\xbf\xd5\xc4\x85\x83\x46\x49\x07\xaa\xa9\xb6\x68\x46\x60\x9b\xac\x00\x61\x49\xad\x93\x40\x2f\xd0\x1a\x41\x13\x14\x3c\x56\x3a\xc7\x41\xe0\x45\xda\xb0\xac\xd2\xd6\x75\xe7\x05\x91\xbc\xd9\x94\x76\xb0\x6b\x54\xe6\xa4\x56\xc9\x10\x1a\x55\x92\x16\x88\xa5\x5a\x18\x27\x45\x59\x9e\xc9\x8b\x76\x0d\x7d\xc8\xa5\x15\xdb\x92\x98\x24\x1a\x51\x03\xad\xe4\x2f\x48\x7d\x17\x8c\x9e\x04\xc7\x22\x27\x8b\x0a\x50\x88\xb9\xf5\x1b\x67\x6b\x52\xcb\xeb\x29\x88\x5c\xd4\x0e\x0d\x28\x51\xd1\x31\x3b\xa3\x2b\x5e\xb1\x42\x77\xd2\xe6\x00\x73\xad\x14\x32\xb3\x16\x6a\xa1\xb0\x0c\xbe\x94\x0c\xbd\xc7\x54\xda\x90\x05\x84\x02\xad\x30\x05\x12\xfe\xf7\x35\x3c\xac\xa7\x24\x44\x21\xf7\x05\x1a\xf2\x5d\x36\xa6\x38\x33\x0b\xe4\x04\x16\x4b\xa2\x7a\xc4\x4e\x48\x3a\xb6\xc7\xec\x73\x61\x67\xeb\xc8\x2d\x69\x79\xf5\xdc\xb2\xd0\xd8\x86\xf5\x97\x6b\xf5\xca\x85\xb3\xd8\x28\x77\xd1\x52\xf0\xf9\xbc\x11\x35\x29\xe5\xe1\xe1\xd3\xcd\xe6\xd3\x03\x18\xad\x1d\x64\x68\x9c\xdc\xc9\x8c\xfc\xec\x2a\x13\xd7\xa3\xfe\x93\x64\x08\x57\xf4\xf5\x7a\xc4\x9e\x5f\x1b\x79\xa4\x75\x07\x3c\xc3\xd5\x01\xcf\xd7\x29\xc0\x42\x64\x05\x64\xa5\x44\xe5\x42\x7c\x10\xc7\x3e\x0b\x78\x27\x66\x65\xb9\x02\xa5\x01\x7d\x52\x4c\x9e\xd6\x25\x43\xa6\xb3\x93\x25\x29\x6f\xd3\x6d\x22\x1a\x24\xbd\x27\x6a\xd9\x77\xc8\x5d\xac\xf7\x77\x2b\x2a\x84\x4c\xf8\x8d\xc9\x90\xe4\x41\xff\x66\x80\xc2\x9e\xc7\xc6\x8a\x01\xe4\xd2\x60\xe6\xb4\x39\xb3\x0e\x05\x91\x0e\x81\xb6\x03\x9b\x19\x59\x3b\x1f\x44\x7b\x54\x68\x84\x93\x6a\x0f\x5f\x1f\x66\x7d\xd1\x6d\x90\xa6\x27\xb3\x4d\x01\xbe\x62\x85\x14\x22\x64\xc9\xc6\x72\x0c\x51\xe4\xfc\xd5\x20\xcc\x75\x55\x69\x05\x2b\xe2\x2f\x5a\xce\x8b\x14\x48\x21\xa9\x4a\xef\xf8\x85\x17\xee\xe2\x40\x2f\xcc\x4c\x9d\xe1\xf7\xb7\x93\xf7\xac\x9c\x4a\x28\xb1\xc7\x8a\x56\x7a\x43\x73\xf0\x6e\x91\x8e\xce\x39\xe0\x6a\x54\x14\x5f\xf4\x58\x94\x96\x79\x02\x01\xeb\x5f\xe6\x0f\x30\xbc\x9d\x12\x1f\x95\x70\x94\xd4\xa2\xae\xc9\xa4\x16\x11\x06\xf5\x21\xb3\xb7\xd3\xa8\x2a\x79\x44\x90\x8a\x0e\x84\x5a\xec\xf1\x3a\x4d\xee\x32\x01\x51\xa1\x37\x24\xfd\x4d\x26\xd2\xcc\xb8\xe4\x8e\x2d\x78\xf9\xca\xcb\xe9\x5f\xd3\x49\x2f\xbe\xa5\x17\x30\x84\x4d\x21\x2d\xb3\x02\xb6\xd0\x4d\x99\x93\x3c\x07\xac\x1d\x58\xca\xc0\x2e\x49\x32\xc1\xc5\x62\x3e\x9b\xa3\x71\x6b\xe1\x0a\xaa\x18\x7c\x28\x3f\xee\x3d\x24\x8a\xf4\xec\x17\x3c\xc7\x47\xc9\x10\xee\xe5\x6e\x27\x11\x0a\x2c\x4b\x2f\x8f\x11\x15\x3a\x34\x9c\xa2\x7e\xf6\x16\x47\x9f\xb6\xc9\x21\x29\x89\xff\x98\x0c\x01\x40\xd7\xa8\xac\x2d\x21\x2f\x78\x0f\x8c\x75\xe3\x20\x2f\x6e\x27\xd3\x37\x69\x8d\x15\xd0\x07\xf2\xb7\x66\x6b\x9d\x74\x8d\x43\x98\x4e\xde\xbc\x63\x63\xd3\xab\x7e\xad\x69\xac\xaf\x2f\xbc\x60\x2b\x9d\xf7\x9f\x64\x98\x17\x3d\x82\xc9\x5d\x5e\x3c\x51\x55\x5e\xd0\x0e\x7e\x99\x17\x2c\xdb\xfd\xc7\x35\x31\x63\x7b\x02\xc6\x0c\xe5\x74\xad\x4b\xbd\x3f\x13\x4f\xad\x2a\x6d\xb3\xa5\x3a\x74\x25\xf2\xdc\xa0\x25\x36\xe0\x28\x05\x2c\xd7\xd7\x5d\xce\x8d\xd9\x23\x86\xd8\x71\x9a\x4e\xd2\xf7\xec\xa4\xa5\x3e\xa1\x09\x31\xab\x93\xa1\xa7\x58\x53\xd1\xc7\x1c\xae\x5c\x81\x0a\x14\xba\xd7\x93\x11\xc8\x14\x53\x10\x70\xf3\x7a\x02\x35\x9a\x40\x8b\x0e\xb9\xc7\x9d\x68\x4a\x67\x29\x46\x78\x2d\x5c\x51\xea\x37\x98\xe9\xaa\x42\x95\x63\x7e\x9d\x44\xd6\x03\xbb\x24\xd5\x5c\xab\x9d\xdc\x37\xa6\xcb\x1e\x94\xb5\x88\x27\x62\xa0\x3c\x83\xe0\x52\x12\x36\x0c\x59\xed\xd1\xff\x9d\x86\xdc\x88\x53\x0c\xab\x20\x3b\x55\x4a\xa3\x2b\x32\x7b\x2f\xbf\x70\x2d\x72\xe2\x80\x70\x3b\x49\xdf\xa5\x93\xf4\x96\x49\x49\x67\xb1\xdc\x8d\x42\xc1\x31\x68\x9d\x5f\xb9\x45\xa8\x04\x31\x72\x14\xb2\xf4\xd9\x5a\x47\xc5\x11\xe5\x5e\x02\x6c\x37\xc4\x65\x86\x43\xfe\x22\x11\x68\xd5\x1e\x9b\x72\xca\xa0\x7d\x94\xaa\xa1\x94\x0a\x81\x3c\xae\x73\xa3\x64\xf8\x1c\xb4\xa4\x6d\xbe\x8b\xc1\xca\xec\x73\x35\x92\x6a\xa7\xd3\xe4\x2e\x08\x1a\xce\x99\xc0\xf4\xed\xdb\x34\xfe\x4d\x92\xf0\x96\x7c\x6b\x85\x84\xe0\xf8\xe3\x67\x61\x0f\xc1\xbd\x3e\x0b\xa9\x9c\x90\x8a\xc0\x18\x66\xda\xe4\x94\xb4\x82\x84\xff\x6f\xfc\x5f\x2d\x30\x5a\xae\xa3\xa2\x29\xc1\x59\xab\x33\x29\x7c\xb9\x94\xca\x8b\x14\x92\xfb\x72\xd7\x1a\x6a\xaf\xd1\x42\x4e\x61\xa7\x49\x1b\xd2\xb2\xa6\x05\x79\xd7\x88\x4f\xf3\x35\x57\xed\x5b\xdf\x0c\x19\x4f\x58\x2b\xf7\x0a\xf3\x60\x1f\xae\x02\xcf\x19\xe9\xaa\x78\xad\x75\x49\xd5\xd9\xc1\x49\x10\x7f\xb5\xc1\xa3\xd4\x8d\x25\x3f\x0a\xa4\xd2\x44\xee\x32\x76\xba\x31\xad\x1e\xd7\x68\xac\xb4\x0e\x64\x5d\xa7\xee\xdb\xdf\xf8\x24\xe9\xfb\xb9\x5d\x92\x21\xfc\x11\x81\xdb\x4e\x1a\xeb\x38\x19\x73\x9a\xf9\xf2\xf0\xca\xb6\x0b\x21\x13\xb5\xd8\xca\x52\x3a\x0a\x5c\xa7\x03\xa0\x6c\x2b\x7d\x0b\x69\x3c\xbc\xa4\xc7\xf1\x30\x8a\xfd\xe5\xbc\x07\x7a\xb8\x70\xaa\x0e\x30\x56\x42\x79\x1c\x60\x09\x13\x33\xaa\x58\xae\x6f\x14\xba\x8a\xcc\xab\x15\x53\x0b\xe7\xb5\x54\x46\x50\xa0\x41\x38\xa1\x37\x63\x53\xb5\x91\xf1\xe6\xe6\xc2\x75\x52\x80\x0f\x52\x31\x7d\x5e\xcc\x47\xd2\x49\xc2\x4a\x0e\x55\xb2\x84\x11\x8a\x89\x7b\x0f\x68\xa3\xf5\x8a\xad\xfc\xff\x03\xe1\xb7\x13\x40\x95\xc7\x6f\xb7\x93\xc9\x35\x29\x42\x94\xa5\x0e\xb0\xc3\xa3\xe5\x27\xbe\x90\x02\x7c\x42\x8f\x26\x62\xbc\xf8\x94\xe2\xd8\x2f\x28\x76\x7a\xa0\xf2\x45\xc8\xdf\x46\xc7\x38\x68\x21\x4a\x7a\x19\x24\xd0\xf1\xd9\xf1\xf8\x1f\x3a\x04\x63\x16\xe2\x5e\xc0\xfd\xc7\xf9\x7a\x5c\x1b\xfd\xed\x3c\x82\x13\x2b\x3b\x7a\xb7\x13\xe5\xc1\x8b\x4b\x96\x89\x51\x12\x58\x64\xad\xd2\xde\x2e\x7d\x70\x52\xc9\x50\xb6\x90\xaa\xe7\xfb\x41\x7d\x1e\x5d\x53\xde\xbc\x5f\x3d\xb4\xa0\x2a\x66\xc4\x14\x5e\xf0\x52\x0f\x53\xbf\xef\xa7\xcf\xbd\x94\x62\xf7\xfb\x7e\xfa\xc4\x4b\x19\xb3\x3a\xfc\xd1\xdb\x8d\x35\xa6\x15\x39\x91\x36\x07\x4b\x5e\x19\xb5\x71\x15\xfa\x8e\x0e\x0c\x5f\x47\x85\x75\xa0\xc9\xab\xa5\x87\x89\x41\xd2\x86\xad\x6e\x14\x03\x6c\xaf\xee\xb0\xf8\xa9\xbd\xc9\x86\xeb\xc6\x16\xbe\xcd\xb4\x51\xf1\x21\xbb\x05\x1f\x3c\x81\x74\x51\xd7\x8c\xd9\x48\xac\x16\x09\x7a\x97\xb6\xb0\xc5\x42\xaa\x36\x1f\x79\x88\xd3\x07\x88\x94\x7b\x5c\x81\xac\xdd\xa7\x7b\xb9\x50\x30\x60\x23\xa8\xee\xcf\x3a\x28\x7d\xe2\x33\x89\xb3\x0b\x77\xe8\xe0\x75\xb0\x34\x27\xb7\xab\x98\xdf\x2f\x83\x94\x2a\xf0\x56\x64\x87\x97\x7d\x2a\x4d\x86\x9e\xfe\xed\xfb\x69\x7a\xfb\xc3\xbb\xf4\xfd\xb3\x02\x11\x3d\x7e\xfa\x6c\xe9\xed\xf7\x96\xbe\x7d\xb6\x74\xfa\xbd\xa5\xaf\x9f\x2d\x7d\xfd\xbd\xa5\x6f\x92\x61\x4d\xa6\x1a\x84\x0d\xff\xa0\x0d\x14\x88\x4f\x37\x0c\x9e\x2c\x0c\x94\x7f\x78\x69\x21\x6c\x74\x28\x00\x60\x6b\xcc\x08\x7c\xf7\x62\xc8\x7b\x44\x7c\x91\x0c\x5b\xcf\x24\x80\xb0\x03\xf1\x3c\x29\x41\x21\x2c\x88\x68\xe0\x64\x18\xf1\x97\xf7\x0e\x90\xce\x3b\x42\x80\xba\x6c\x72\x06\x57\x64\x12\x3f\x07\x18\xf5\x9b\x9b\x66\xdb\xb5\x2e\x83\x2c\xcb\x7d\x7f\x1d\x1d\xbf\xc7\x57\xc8\x43\x1c\xee\x5c\x67\xad\xc7\xf5\x2f\x83\x82\xeb\x94\x1c\x7f\xf1\xfb\xec\xf3\xfa\xd3\xe2\x47\x78\x20\x44\x67\xfb\x41\xe5\x9b\x5a\x12\x8b\x9f\xf5\x9a\xc2\xcc\xb7\x35\xd4\x25\xc3\x60\x53\x60\xa9\x15\xd5\x51\x52\x65\x90\x86\xe4\xb7\x15\xb5\x6c\x97\xb2\x53\xb0\x77\xfa\xa2\x7a\x21\xb2\x42\x2a\xec\xc6\x0b\xd1\x52\x6f\x26\xe9\xed\xf4\xdd\x85\x1f\x4f\xdf\xbc\xa3\xbc\xf1\x81\x52\xd4\x08\x1a\x15\x12\x3d\x27\x79\x8e\x2a\xce\xff\xf6\xc7\x64\x18\x94\x13\x2a\x79\x2e\x0d\x64\x59\xfe\x7f\xbb\xb9\x07\x85\xaa\x1b\x3c\x71\x4b\x92\x65\xf9\x4d\x27\x64\xcc\x6c\xa1\xda\xf8\x2e\x41\x5e\x52\xf6\xbc\xc3\x13\xde\x93\xd0\xe7\x84\x40\xa7\x9c\xd2\x91\x7d\xf5\x24\x1f\x78\xa4\x1d\xa6\x42\x61\x64\xc2\xa5\x5d\x5a\xc0\x6f\xa2\xaa\x4b\xf4\x84\xda\xac\x49\xe9\xb7\x6b\x36\x88\x21\xa9\xf6\x23\x9e\xb0\xc4\xf4\x1d\x00\x7a\x87\x24\x7d\x31\xea\xc6\x6e\x54\x21\x06\x3e\x2b\xf4\xba\x40\xfb\xb2\xa7\xf4\xc7\x58\x61\x78\xd4\x53\x13\x29\xef\x1b\xe6\xec\xd4\xbd\x82\xa4\x77\x14\xca\xef\x19\xeb\x46\x5b\xfe\x9d\x29\xef\x5e\x36\xe5\xf3\xa7\xdc\x07\xce\xef\x63\x4b\x14\x2c\x29\xf2\xbc\x87\x0c\x08\x41\x5c\x18\x33\x58\xaf\x85\x7c\x94\x31\x22\x7b\xf1\xc3\x34\x49\x32\x53\x8e\x8f\x68\xe4\xce\xb7\x96\xf3\xaf\x9f\xba\x63\xba\xb8\x11\xee\x42\x25\xa8\x18\xf2\xe7\x72\xb7\x43\xe3\xc3\xa9\x9d\xe2\x3c\x99\xf6\x71\x60\xb6\x0b\x61\x6f\x74\x53\x87\xc9\x44\x07\x73\x36\x5c\xf3\xc8\xb6\xee\xa4\xa1\x42\x57\xe8\x9c\x05\xb8\xba\xbd\x86\xaf\x8d\x82\xaa\x29\x9d\x24\xbf\x88\xe9\x3d\x17\x58\x69\x65\x47\xa0\x55\xc0\x23\x22\x2b\x58\x62\xf0\x67\xf8\x11\x4e\xcb\xd5\x8b\x43\xb4\xb0\x3e\x6e\xf7\x1b\x6f\x3c\x69\x10\x75\x6d\x74\x6d\xa4\x70\x58\x9e\xc9\x9e\x57\xd3\x6b\xb8\x9a\xe5\x47\xa1\x32\xcc\xaf\x61\x1e\x03\xc9\x0f\x58\xb8\x27\x3b\x2b\x51\xc9\x8c\x10\x63\x20\x5d\xe9\x9c\x34\x7b\x31\xd3\x93\x8a\x9a\x80\x5a\x2b\xcb\x56\xf3\xfa\x8a\xac\x10\x9e\xef\xb4\xd5\x69\xe8\xc1\xe7\xba\xb0\xec\x79\xc6\x23\x58\x51\xa2\x30\x6a\x1c\xbd\xd1\xb3\x95\x26\x77\x97\x8f\xd3\x1b\xff\x22\xf1\xf3\x5a\x6f\xc9\x7c\xe4\x3d\xa9\x1b\x8e\xf8\xc1\x73\x44\x7f\x9c\xfc\xba\x11\x15\x23\x05\xbf\x36\xc0\xb2\xdc\xf7\xc0\xc9\x90\x3a\x60\x6e\xd6\xf7\xc2\xe1\x49\x90\xe8\x46\x37\xfb\xa2\x9b\xf6\x66\x22\x0e\x0b\x88\xe4\x72\x0d\xce\x88\x1d\x95\xa5\x98\x25\x4f\xb8\x85\xad\xd1\x27\x0f\x26\x19\x72\x44\x74\x57\x6a\x7d\x68\x6a\x66\x60\xaf\x9f\x92\x26\x13\x6d\x9e\x21\x80\x98\x85\x2f\x86\x92\xab\xd9\x86\x5c\xd0\x5c\xa0\xbc\xa7\xde\x11\x11\x05\x3f\xf0\xa8\x5e\x52\x1f\x97\xa3\x69\xa7\xc0\xb4\x86\xc5\x25\x5f\x41\x53\x9e\xaf\xd3\xe4\x2e\x14\xe7\xa0\xa1\x71\xd4\x44\x8e\xbb\x5b\xd8\x9e\x6b\x61\xed\x38\x2f\xb2\x7a\xf0\x1f\xac\x24\x28\x8e\x86\xbb\xd4\x80\x14\xdb\xea\xd8\x6a\xdc\xa2\xa3\xb4\x48\xae\x14\x9a\x48\x22\xef\x05\x0e\x96\xeb\x4a\xd1\xfd\xea\xc1\x6b\xe0\xb7\xe5\xcb\xa8\x79\x3e\xfb\x75\x31\xdb\x50\x0c\x16\xce\xd5\x3f\xde\xdc\xe8\x1a\xd5\xb1\x56\xa9\x42\x77\xb3\x13\x7f\xa5\x85\xab\xca\x21\x71\x97\x89\x23\x0a\x67\xc3\xd4\xa1\x43\x16\x5b\xa4\x32\x60\x70\xe7\xc7\x87\xdc\xa5\x36\xdb\x92\xeb\x79\x07\xd5\x2d\xa9\xee\x28\x73\xcc\x61\x7b\xe6\x91\x54\xae\x6c\x9a\xe9\xaa\x55\x24\x9d\x31\xd6\x35\x57\x7e\xda\x37\x9d\xbc\x4b\x7f\xf8\x47\x3a\x9d\x4e\xe9\x6f\x90\xbc\xbc\xea\x5d\xca\xff\xb3\xea\x1e\xdb\x1c\xfc\xc4\xcb\x5b\x00\xdc\xcf\x64\x3d\x2f\xef\xcd\x36\x06\x16\x71\x00\x1d\x3e\xa6\x8c\xf0\xd3\x39\x3a\xfe\xe8\x62\x7c\xeb\x0b\x97\x0d\x73\x8b\x16\x89\x12\x16\xdb\x69\x93\x61\xff\x88\x17\x96\x8e\xc2\xd8\xfd\x12\x35\x33\xb3\xfd\x9c\x74\x91\xdc\x08\x89\xf1\xe6\x57\xf6\xa5\xcb\x82\x50\x53\x9c\x1e\x07\xfc\xf3\x77\x5a\x91\xbb\x2e\xdf\x06\x4e\x09\xcd\xc8\x7d\xe1\x22\xc0\xe9\x7a\x20\x3f\x9f\xee\x00\xd4\xcd\x01\xcf\x5c\x0e\x08\xa2\x11\x96\xeb\xf0\x94\x8d\x45\x9e\xc7\x20\xed\x74\x8c\xa7\x44\xa5\x1f\x5d\x3b\xb4\x0c\x36\xeb\xc6\x50\xe5\xa1\x1d\x1f\x34\xf5\x22\x3a\x6f\xf8\x6e\x82\xa0\x23\x21\x48\xec\x8d\xa1\x02\xd8\x64\x9c\x29\x09\xbc\x86\xb1\xfb\x25\x47\xb5\x90\xc6\xcf\x9c\x97\x1f\xe0\x8f\x2f\x8f\xf0\x71\xf6\xeb\x02\x56\x5f\x36\xf0\xf3\x62\xb5\xf8\x3a\xdb\x2c\xee\x61\xb9\xba\x5f\xfe\xba\xbc\x7f\x9c\x7d\xa2\x80\x5b\x7c\xdd\x2c\x3f\x2c\xe7\xb3\xcd\xe2\xe6\x97\xc5\x1f\xb0\x9e\x2d\xbf\x3e\xc0\x87\x2f\x5f\x61\x31\x9b\x7f\x84\xf9\xa7\xe5\x62\xb5\x21\x5e\xf8\xeb\xc7\xd9\xaf\xcb\xd5\xcf\xb0\xdc\x3c\xc0\x97\xdf\x56\xf0\xb8\x5a\xfe\xcf\xe3\x02\x06\xf3\x2f\x9f\x3f\x7f\x59\xc1\x6a\xf6\x79\x31\xa0\xb5\x8f\x2b\x7a\xb2\x58\x6d\x60\xf3\x71\xf9\x00\x9f\x96\xab\x05\x7c\x79\xdc\xa4\xc9\x5d\xde\xd4\x25\xf3\x3b\xce\xf8\x2e\x87\x82\xe9\x80\x58\x8b\x92\x6c\xd2\x59\x87\xf2\x27\x5a\xa8\xa5\xda\x8f\x4b\x79\xe0\xc1\x04\x5a\x2b\xf6\x18\x5d\xd6\x92\x52\xb8\x27\xe2\x12\xa8\x8d\x2b\xf8\xc6\x2d\xf4\x6e\xa5\x54\x07\xb0\xda\x57\x75\xd6\x23\x77\x98\xd4\x8f\x59\xea\x3e\x55\x58\xe7\xdb\x40\x7e\x47\xa0\x77\x4f\x95\x36\xd7\x27\x45\x9e\xbc\x26\x23\xe1\x11\xcd\x19\x6e\x27\x60\x31\xd3\x2a\xb7\xa3\x38\x4e\x61\xca\x06\x2b\xcd\x1d\x42\x8d\xdc\xb3\xfa\x31\x98\xdc\x81\xd2\xcc\x7c\x6c\xec\x73\xc8\x1b\x13\x0a\x02\xdc\x4e\x23\x35\x70\xb2\x42\xa8\xd1\x48\x9d\xa7\x49\xa7\x88\xdb\x09\x2d\x22\x05\x91\x63\xe0\x37\x67\x04\xed\x68\x0c\xf5\xed\x5b\x3c\xf3\x56\x3a\x3f\xa6\x15\xea\x0f\xcf\xf1\x12\x68\xd4\xbb\x4c\x1d\x7c\xfc\x3c\x9b\xb7\x41\x34\xf0\x5d\x69\x81\x65\x0d\xdb\x52\x67\x07\xb8\xd7\x0f\x20\x9c\x13\xd9\xc1\xb2\x22\x1f\xef\xd7\xc0\xb7\xc1\xbb\x52\xeb\xdc\x8f\xc0\xfa\x13\xf6\xcb\xc1\xfa\xb1\x56\x30\x1e\xef\x51\x1d\xf0\x0c\xe3\xb1\x1f\xf6\x83\x13\x29\x7b\xe3\xe5\x88\xb6\xbd\x2d\x09\x0e\xdd\xde\x23\xb1\x4e\x32\x5d\x9f\xfd\x3d\x8a\xb4\x70\xc0\x73\x37\xdf\x65\x3d\xb5\xf3\xfe\xde\xfd\xc2\xab\xc9\x2b\x3f\x7b\x75\x97\x87\xbc\xba\x7d\x15\x9f\xb6\x23\xdd\x3b\x57\xda\xb1\x68\x28\x9c\x99\x39\x98\x5c\x5c\x5a\x48\xdb\x5e\x54\x0c\xe1\x81\x2f\xf3\x88\x27\x73\xae\x9d\xde\x1b\x51\x17\x32\x83\x4c\xd6\x21\x23\x6e\x42\x13\xb4\x93\x7b\x90\x0e\x2b\x2f\xca\x96\xda\xaa\x5a\x72\x0e\x0b\xce\x15\x2f\x84\xfc\x52\x3e\x89\x4b\x7f\x59\xa6\xc9\x9d\xa7\x07\x3f\x7d\x18\xcf\x7f\x9a\x43\xf8\x6f\x08\x3f\x95\xfa\xb4\x93\xb6\x80\xab\x90\x75\xaf\xdb\xa5\xb3\xc5\xc3\xf8\x76\xfa\x2e\xac\x1f\xd2\xf7\xf6\xdd\xfd\xe2\x61\xbc\xb8\x5f\xbc\xf6\x2f\x87\xb0\x31\x94\xd9\xc6\xf7\x8b\x07\x86\xfe\x1e\xca\x66\xba\xaa\xf9\xfe\x40\xab\xa8\x21\xc2\x10\x14\x2b\xbd\x9b\xed\x80\x7b\xa5\xe3\x11\x62\xef\xe6\x9a\xb2\x34\x65\xa5\xf6\xbd\x54\xdf\x11\x33\x4d\xe8\xa8\x71\xf9\x4f\x1d\x83\xbc\x12\xdf\x64\xd5\x54\xe1\x32\x9a\x81\xb1\x56\x59\x63\xa8\x1c\x95\xe7\x98\x71\xd9\x91\xdb\x22\x83\x2d\x14\xe7\xfa\x95\x26\x77\x95\xf8\x36\x8e\xaf\xc3\xf0\x6e\xe9\x5e\x51\xaf\xb2\xd7\x3a\x07\x99\xa3\x08\xb8\xad\xc9\x2e\xc6\x2d\xc9\x30\x80\xe9\x57\x96\xfb\x34\x59\x22\xa5\x12\xb1\xe3\x51\x93\x92\x4e\x8a\x52\xfe\x93\x1b\x6f\xef\xf0\x7f\x84\x4b\xf5\xe6\xb2\x7e\x50\x7b\xc3\xa3\xb8\x17\x6e\xe2\xd3\xa4\xb1\x24\x9a\x8f\x8b\x84\x71\x76\xfb\x2d\xa8\x21\x8e\xa3\x7d\x0d\x0f\x85\xd4\x19\x1e\xc6\x89\xa3\x96\x79\xdb\x33\xf2\x34\x22\xa0\x21\x83\x56\x37\x26\x43\x9e\xab\x85\xd9\x3a\xbb\x98\x70\x1e\xf1\x69\x28\xb5\xda\xa3\xe1\x5a\xee\xb7\x93\x89\xb6\xc8\x79\xd4\x37\x22\x0c\x4d\xa2\xe8\x9c\xa7\xf6\x46\xe4\x98\x26\x81\xa7\x31\xc5\x6c\xfc\x1c\xae\xda\xbf\x34\xae\x6e\x28\x14\x6c\x41\x39\xc1\x3a\xe1\x9a\xee\x9e\xef\xe4\x13\x5a\xb0\x62\x3b\x16\xe0\x8e\xc5\x99\x46\x51\x9e\x8f\xc0\xd6\xe0\xc9\x48\xe7\x50\x85\x84\x5a\x49\xd5\x38\x4c\x93\x40\x32\xa8\x69\xec\xbf\xa6\xa5\xde\x27\x4f\xa0\x47\xa9\xf7\x5d\x09\x60\xb5\x11\x38\xf6\x88\xcb\x9e\x2d\xbd\xbe\xd2\xe1\x32\xa6\xfd\x59\x83\xdc\x81\x69\x94\x62\x8c\x6d\xfd\x95\xf1\x51\x66\xc8\xbf\x61\x38\xf7\xa8\x84\x78\x1d\xfc\xb9\x36\x14\xef\x15\x7c\xa0\xca\xfe\x67\x70\x9e\x3f\x4b\xbd\xef\x5d\x3f\x5f\xc7\x5f\xa4\xd0\x99\xda\xd0\x3f\x63\x51\x13\xa6\x63\xa8\x73\x44\x63\xa8\x9c\x78\xbc\xe1\xd9\xa7\x1d\x03\xa6\x12\x0c\xee\x95\xe3\x2b\x95\x0e\xa9\x41\xab\x0e\xd5\x93\x85\x9b\x9a\x6a\xe9\xa9\xa0\x77\x83\xee\x90\x40\xa3\x3b\x51\xba\x14\x98\x1f\xad\xd0\xc3\xdd\xae\xb0\x5d\x6d\x1b\xe7\x27\x08\xda\x15\x04\xdb\xe9\xb4\xf8\x5f\x04\xbb\xa4\xed\xbb\x9e\x14\x17\x2f\x38\x21\x72\x07\xd4\x07\x66\x50\xe2\x11\x4b\x72\x2b\x5a\xe3\x91\x10\x1c\xd1\x6c\xb5\x95\xee\xec\x43\x68\xc2\x69\x55\x96\xa8\xdc\x08\xf0\x5b\x86\xb5\x63\xf8\xb3\x13\x4e\x94\x80\xc6\x68\x43\x90\xeb\x8d\x47\x4a\xc2\x6a\x9f\x57\xba\x2b\xfc\x12\x1a\x32\x77\x32\x84\xb7\xec\x43\x3f\x70\x44\x72\xf1\xa2\x3e\x14\xb7\xcd\xbe\xe7\x74\x54\x0b\xb7\x25\x56\x44\xf3\x3d\xf0\x94\xc5\x19\xac\x08\x43\x7a\xc6\x30\xa1\x7f\xe1\x35\x8b\x44\x6c\x65\x08\x06\x6b\xf4\x3f\x15\x88\xbe\x95\x02\xcc\x9c\xff\xc5\xcb\x74\xc2\x80\xf3\xaf\x06\x15\xe5\x87\xce\xfd\x42\x34\x31\x2a\x0c\x0f\xb9\x1f\x71\xb8\xd7\xe6\xdc\xde\x18\x6a\x1f\x3d\xc1\x49\x4b\xbd\xa7\x0c\xe6\x6f\x98\x93\xff\x0d\x00\x00\xff\xff\x98\xcc\x07\xa4\x7d\x25\x00\x00") +var _templateServerConfTmpl = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x94\x5a\x5f\x6f\xdb\xb8\xb2\x7f\xd7\xa7\x18\xd8\x0f\x4d\x00\x5b\x71\xdc\x76\x4f\xbb\xb9\x7f\xe0\x4d\xdc\xad\xb1\xad\xe3\xdb\x38\xdd\x5d\x60\x5f\x68\x69\x6c\x11\x96\x48\x2d\x49\xd9\xf5\x39\xd8\xef\x7e\x31\x43\x52\x92\x93\x74\x0f\x4e\x81\xa0\xb6\x44\x0e\xe7\xff\xfc\x66\xe8\x9b\x5a\x1b\x07\xd7\xd7\xef\xdf\x24\xfc\xe9\x5f\xff\x82\x74\x45\x1f\xfe\xfa\x2b\x49\x86\xb0\xbe\x5d\x81\x36\xf0\x78\xb7\x02\x8b\xe6\x80\xe6\x7f\x93\x9b\xda\x68\xa7\xc1\x65\x75\xe2\x3f\xf1\x16\xfe\xe4\xf7\x0c\x72\x3c\x80\x6b\xd4\x00\x8e\xb2\x2c\x21\x33\x28\x1c\x82\x00\xa3\x1b\x87\x39\x2c\x56\xf4\x52\x61\x39\x6a\xd7\x8a\xfa\xc9\x5a\x05\xe8\x0a\x34\x0a\x5d\x58\x9b\x26\x43\x78\xb4\xd8\xae\x9f\x0c\x40\x6e\xe1\xa4\x1b\x10\x06\xbb\xc5\x1b\x23\xf3\x9d\x54\xbb\x64\x08\x42\xe5\x50\x88\x03\x42\x6d\xd0\x93\xcd\x41\xf0\x56\x38\x48\xe3\x1a\x51\x82\x54\x0e\xcd\x56\x64\x18\x96\xf3\x6e\xcc\x41\x3a\x38\x4a\x57\x10\x79\xd3\xd1\x6e\x57\x13\x2f\x0b\x7f\xf8\x51\x28\x07\x4e\x43\xa6\x95\x33\xba\x04\x91\x65\x68\x2d\xd4\xba\x94\x99\x44\x9b\x0c\x41\x1f\xd0\x80\x2b\x10\xbe\xae\x96\x23\xde\x53\x35\xd6\x45\x41\xb7\xd2\xe0\x51\x94\x65\x32\x04\xd3\x94\x68\x61\xab\xfd\x6a\xfa\x5b\x3f\x2e\xaf\xd6\xb3\xd5\xf9\xc1\xf7\x0a\x94\x56\xe3\x5f\xa5\xca\xf5\xd1\x82\x3d\x59\x87\x95\xf5\x94\x33\xa1\x60\x27\x0f\x5e\x1c\xc0\x6f\x35\x71\xe1\xa0\x51\xd2\x81\x6a\xaa\x0d\x9a\x11\xd8\x26\x2b\x40\x58\x52\xeb\x24\xd0\x0b\xb4\x46\xd0\x04\x05\x8f\x95\xce\x71\x10\x78\x91\x36\x2c\xab\xb4\x75\xdd\x79\x41\x24\x6f\x36\xa5\x1d\x6c\x1b\x95\x39\xa9\x55\x32\x84\x46\x95\xa4\x05\x62\xa9\x16\xc6\x49\x51\x96\x27\xf2\xa2\x6d\x43\x1f\x72\x69\xc5\xa6\x24\x26\x89\x46\xd4\x40\x2b\xf9\x0b\x52\xdf\x04\xa3\x27\xc1\xb1\xc8\xc9\xa2\x02\x14\x62\x6e\xfd\xc6\xd9\x8a\xd4\xf2\x7a\x0a\x22\x17\xb5\x43\x03\x4a\x54\x74\xcc\xd6\xe8\x8a\x57\x2c\xd1\x1d\xb5\xd9\xc3\xad\x56\x0a\x99\x59\x0b\xb5\x50\x58\x06\x5f\x4a\x86\xde\x63\x2a\x6d\xc8\x02\x42\x81\x56\x98\x02\x09\xff\xdb\x0a\x1e\x56\x53\x12\xa2\x90\xbb\x02\x0d\xf9\x2e\x1b\x53\x9c\x98\x05\x72\x02\x8b\x25\x51\x3d\x60\x27\x24\x1d\xdb\x63\xf6\xb9\xb0\xb3\x55\xe4\x96\xb4\xbc\x7c\x6e\x59\x68\x6c\xc3\xfa\xcb\xb5\x7a\xe5\xc2\x59\x6c\x94\x9b\x68\x29\xf8\x7c\x5a\x8b\x9a\x94\xf2\xf0\xf0\xe9\x6a\xfd\xe9\x01\x8c\xd6\x0e\x32\x34\x4e\x6e\x65\x46\x7e\x76\x91\x89\xcb\x51\xff\x49\x32\x84\x0b\xfa\x7a\x39\x62\xcf\xaf\x8d\x3c\xd0\xba\x3d\x9e\xe0\x62\x8f\xa7\xcb\x14\x60\x2e\xb2\x02\xb2\x52\xa2\x72\x21\x3e\x88\x63\x9f\x05\xbc\x13\xb3\xb2\x5c\x81\xd2\x80\x3e\x2a\x26\x4f\xeb\x92\x21\xd3\xd9\xca\x92\x94\xb7\xee\x36\x11\x0d\x92\xde\x13\xb5\xec\x3b\xe4\x2e\xd6\xfb\xbb\x15\x15\x42\x26\xfc\xc6\x64\x48\xf2\xa0\x7f\x33\x40\x61\x4f\x63\x63\xc5\x00\x72\x69\x30\x73\xda\x9c\x58\x87\x82\x48\x87\x40\xdb\x82\xcd\x8c\xac\x9d\x0f\xa2\x1d\x2a\x34\xc2\x49\xb5\x83\x2f\x0f\xb3\xbe\xe8\x36\x48\xd3\x93\xd9\xa6\x00\x5f\xb0\x42\x0a\x11\xb2\x64\x63\x39\x86\x28\x72\xfe\x6c\x10\x6e\x75\x55\x69\x05\x4b\xe2\x2f\x5a\xce\x8b\x14\x48\x21\xa9\x4a\x6f\xf9\x85\x17\xee\xec\x40\x2f\xcc\x4c\x9d\xe0\xb7\xb7\x93\xf7\xac\x9c\x4a\x28\xb1\xc3\x8a\x56\x7a\x43\x73\xf0\x6e\x90\x8e\xce\x39\xe0\x6a\x54\x14\x5f\xf4\x58\x94\x96\x79\x02\x01\xab\x5f\x6e\x1f\x60\x78\x3d\x25\x3e\x2a\xe1\x28\xa9\x45\x5d\x93\x49\x2d\x22\x0c\xea\x7d\x66\xaf\xa7\x51\x55\xf2\x80\x20\x15\x1d\x08\xb5\xd8\xe1\x65\x9a\xdc\x64\x02\xa2\x42\xaf\x48\xfa\xab\x4c\xa4\x99\x71\xc9\x0d\x5b\xf0\xfc\x95\x97\xd3\xbf\xa6\x93\x5e\x7c\x4b\x2f\x60\x08\xeb\x42\x5a\x66\x05\x6c\xa1\x9b\x32\x27\x79\xf6\x58\x3b\xb0\x94\x81\x5d\x92\x64\x82\x8b\xc5\xed\xec\x16\x8d\x5b\x09\x57\x50\xc5\xe0\x43\xf9\x71\xef\x21\x51\xa4\x67\xbf\xe0\x29\x3e\x4a\x86\x70\x27\xb7\x5b\x89\x50\x60\x59\x7a\x79\x8c\xa8\xd0\xa1\xe1\x14\xf5\xb3\xb7\x38\xfa\xb4\x4d\x0e\x49\x49\xfc\xc7\x64\x08\x00\xba\x46\x65\x6d\x09\x79\xc1\x7b\x60\xac\x1b\x07\x79\x71\x3d\x99\xbe\x49\x6b\xac\x80\x3e\x90\xbf\x35\x1b\xeb\xa4\x6b\x1c\xc2\x74\xf2\xe6\x1d\x1b\x9b\x5e\xf5\x6b\x4d\x63\x7d\x7d\xe1\x05\x1b\xe9\xbc\xff\x24\xc3\xbc\xe8\x11\x4c\x6e\xf2\xe2\x89\xaa\xf2\x82\x76\xf0\xcb\xbc\x60\xd9\xee\x3e\xae\x88\x19\xdb\x13\x30\x66\x28\xa7\x6b\x5d\xea\xdd\x89\x78\x6a\x55\x69\x9b\x0d\xd5\xa1\x0b\x91\xe7\x06\x2d\xb1\x01\x07\x29\x60\xb1\xba\xec\x72\x6e\xcc\x1e\x31\xc4\x0e\xd3\x74\x92\xbe\x67\x27\x2d\xf5\x11\x4d\x88\x59\x9d\x0c\x3d\xc5\x9a\x8a\x3e\xe6\x70\xe1\x0a\x54\xa0\xd0\xbd\x9e\x8c\x40\xa6\x98\x82\x80\xab\xd7\x13\xa8\xd1\x04\x5a\x74\xc8\x1d\x6e\x45\x53\x3a\x4b\x31\xc2\x6b\xe1\x82\x52\xbf\xc1\x4c\x57\x15\xaa\x1c\xf3\xcb\x24\xb2\x1e\xd8\x25\xa9\x6e\xb5\xda\xca\x5d\x63\xba\xec\x41\x59\x8b\x78\x22\x06\xca\x13\x08\x2e\x25\x61\xc3\x90\xd5\x1e\xfd\xdf\x69\xc8\x8d\x38\xc6\xb0\x0a\xb2\x53\xa5\x34\xba\x22\xb3\xf7\xf2\x0b\xd7\x22\x27\xf6\x08\xd7\x93\xf4\x5d\x3a\x49\xaf\x99\x94\x74\x16\xcb\xed\x28\x14\x1c\x83\xd6\xf9\x95\x1b\x84\x4a\x10\x23\x07\x21\x4b\x9f\xad\x75\x54\x1c\x51\xee\x25\xc0\x76\x43\x5c\x66\x38\xe4\xcf\x12\x81\x56\xed\xb1\x29\xa7\x0c\xda\x47\xa9\x1a\x4a\xa9\x10\xc8\xe3\x3a\x37\x4a\x86\xcf\x41\x4b\xda\xe6\xbb\x18\xac\xcc\x3e\x57\x23\xa9\xb6\x3a\x4d\x6e\x82\xa0\xe1\x9c\x09\x4c\xdf\xbe\x4d\xe3\xdf\x24\x09\x6f\xc9\xb7\x96\x48\x08\x8e\x3f\x7e\x16\x76\x1f\xdc\xeb\xb3\x90\xca\x09\xa9\x08\x8c\x61\xa6\x4d\x4e\x49\x2b\x48\xf8\x5f\xe3\xff\x69\x81\xd1\x62\x15\x15\x4d\x09\xce\x5a\x9d\x49\xe1\xcb\xa5\x54\x5e\xa4\x90\xdc\x17\xdb\xd6\x50\x3b\x8d\x16\x72\x0a\x3b\x4d\xda\x90\x96\x35\x2d\xc8\xbb\x46\x7c\x9a\xaf\xb9\x6a\xd7\xfa\x66\xc8\x78\xc2\x5a\xb9\x53\x98\x07\xfb\x70\x15\x78\xce\x48\x57\xc5\x6b\xad\x4b\xaa\xce\x0e\x8e\x82\xf8\xab\x0d\x1e\xa4\x6e\x2c\xf9\x51\x20\x95\x26\x72\x9b\xb1\xd3\x8d\x69\xf5\xb8\x46\x63\xa5\x75\x20\xeb\x3a\x75\xdf\xfe\xc6\x27\x49\xdf\xcf\xed\x92\x0c\xe1\xf7\x08\xdc\xb6\xd2\x58\xc7\xc9\x98\xd3\xcc\xfd\xc3\x2b\xdb\x2e\x84\x4c\xd4\x62\x23\x4b\xe9\x28\x70\x9d\x0e\x80\xb2\xad\xf4\x2d\xa4\xf1\xf0\x92\x1e\xc7\xc3\x28\xf6\x17\xb7\x3d\xd0\xc3\x85\x53\x75\x80\xb1\x12\xca\xe3\x00\x4b\x98\x98\x51\xc5\x62\x75\xa5\xd0\x55\x64\x5e\xad\x98\x5a\x38\xaf\xa5\x32\x82\x02\x0d\xc2\x11\xbd\x19\x9b\xaa\x8d\x8c\x37\x57\x67\xae\x93\x02\x7c\x90\x8a\xe9\xf3\x62\x3e\x92\x4e\x12\x56\x72\xa8\x92\x25\x8c\x50\x4c\xdc\x7b\x40\x1b\xad\x17\x6c\xe5\xff\x0e\x84\xdf\x4e\x00\x55\x1e\xbf\x5d\x4f\x26\x97\xa4\x08\x51\x96\x3a\xc0\x0e\x8f\x96\x9f\xf8\x42\x0a\xf0\x09\x3d\x9a\x88\xf1\xe2\x53\x8a\x63\xbf\xa0\xd8\xe9\x81\xca\x17\x21\x7f\x1b\x1d\xe3\xa0\x85\x28\xe9\x79\x90\x40\xc7\x67\xc7\xe3\x7f\xe8\x10\x8c\x59\x88\x7b\x01\x77\x1f\x6f\x57\xe3\xda\xe8\x6f\xa7\x11\x1c\x59\xd9\xd1\xbb\x9d\x28\xf7\x5e\x5c\xb2\x4c\x8c\x92\xc0\x22\x6b\x95\xf6\x76\xe9\x83\x93\x4a\x86\xb2\x85\x54\x3d\xdf\x0f\xea\xf3\xe8\x9a\xf2\xe6\xdd\xf2\xa1\x05\x55\x31\x23\xa6\xf0\x82\x97\x7a\x98\xfa\x7d\x3f\x7d\xee\xa5\x14\xbb\xdf\xf7\xd3\x27\x5e\xca\x98\xd5\xe1\x8f\xde\x6e\xac\x31\xad\xc8\x89\xb4\xd9\x5b\xf2\xca\xa8\x8d\x8b\xd0\x77\x74\x60\xf8\x32\x2a\xac\x03\x4d\x5e\x2d\x3d\x4c\x0c\x92\x36\x6c\x74\xa3\x18\x60\x7b\x75\x87\xc5\x4f\xed\x4d\x36\x5c\x35\xb6\xf0\x6d\xa6\x8d\x8a\x0f\xd9\x2d\xf8\xe0\x11\xa4\x8b\xba\x66\xcc\x46\x62\xb5\x48\xd0\xbb\xb4\x85\x0d\x16\x52\xb5\xf9\xc8\x43\x9c\x3e\x40\xa4\xdc\xe3\x0a\x64\xed\x3e\xdd\xcb\x85\x82\x01\x1b\x41\x75\x7f\xd6\x5e\xe9\x23\x9f\x49\x9c\x9d\xb9\x43\x07\xaf\x83\xa5\x39\xb9\x5d\xc4\xfc\x7e\x1e\xa4\x54\x81\x37\x22\xdb\xbf\xec\x53\x69\x32\xf4\xf4\xaf\xdf\x4f\xd3\xeb\x1f\xde\xa5\xef\x9f\x15\x88\xe8\xf1\xd3\x67\x4b\xaf\xbf\xb7\xf4\xed\xb3\xa5\xd3\xef\x2d\x7d\xfd\x6c\xe9\xeb\xef\x2d\x7d\x93\x0c\x6b\x32\xd5\x20\x6c\xf8\x07\x6d\xa0\x40\x7c\xba\x61\xf0\x64\x61\xa0\xfc\xc3\x4b\x0b\x61\xad\x43\x01\x00\x5b\x63\x46\xe0\xbb\x17\x43\xde\x23\xe2\x8b\x64\xd8\x7a\x26\x01\x84\x2d\x88\xe7\x49\x09\x0a\x61\x41\x44\x03\x27\xc3\x88\xbf\xbc\x77\x80\x74\xde\x11\x02\xd4\x65\x93\x33\xb8\x22\x93\xf8\x39\xc0\xa8\xdf\xdc\x34\x9b\xae\x75\x19\x64\x59\xee\xfb\xeb\xe8\xf8\x3d\xbe\x42\x1e\xe2\x70\xe7\x3a\x6b\x3d\xae\x7f\x19\x14\x5c\xa6\xe4\xf8\xf3\xdf\x66\x9f\x57\x9f\xe6\x3f\xc2\x03\x21\x3a\xdb\x0f\x2a\xdf\xd4\x92\x58\xfc\xac\xd7\x14\x66\xbe\xad\xa1\x2e\x19\x06\xeb\x02\x4b\xad\xa8\x8e\x92\x2a\x83\x34\x24\xbf\xad\xa8\x65\x3b\x97\x9d\x82\xbd\xd3\x17\xd5\x0b\x91\x15\x52\x61\x37\x5e\x88\x96\x7a\x33\x49\xaf\xa7\xef\xce\xfc\x78\xfa\xe6\x1d\xe5\x8d\x0f\x94\xa2\x46\xd0\xa8\x90\xe8\x39\xc9\x73\x54\x71\xfe\xb7\x3f\x26\xc3\xa0\x9c\x50\xc9\x73\x69\x20\xcb\xf2\x7f\xef\xe6\x1e\x14\xaa\x6e\xf0\xc4\x2d\x49\x96\xe5\x57\x9d\x90\x31\xb3\x85\x6a\xe3\xbb\x04\x79\x4e\xd9\xf3\x0e\x4f\x78\x4f\x42\x9f\x13\x02\x9d\x72\x4a\x47\xf6\xd5\x93\x7c\xe0\x91\x76\x98\x0a\x85\x91\x09\x97\x76\x69\x01\xbf\x89\xaa\x2e\xd1\x13\x6a\xb3\x26\xa5\xdf\xae\xd9\x20\x86\xa4\xda\x8d\x78\xc2\x12\xd3\x77\x00\xe8\x1d\x92\xf4\xc5\xa8\x1b\xbb\x51\x85\x18\xf8\xac\xd0\xeb\x02\xed\xcb\x9e\xd2\x1f\x63\x85\xe1\x51\x4f\x4d\xa4\xbc\x6f\x98\xb3\x53\xf7\x0a\x92\xde\x52\x28\xbf\x67\xac\x1b\x6d\xf9\x77\xa6\xbc\x79\xd9\x94\xcf\x9f\x72\x1f\x78\x7b\x17\x5b\xa2\x60\x49\x91\xe7\x3d\x64\x40\x08\xe2\xcc\x98\xc1\x7a\x2d\xe4\xa3\x8c\x11\xd9\x8b\x1f\xa6\x49\x92\x99\x72\x7c\x40\x23\xb7\xbe\xb5\xbc\xfd\xf2\xa9\x3b\xa6\x8b\x1b\xe1\xce\x54\x82\x8a\x21\x7f\x2e\xb7\x5b\x34\x3e\x9c\xda\x29\xce\x93\x69\x1f\x07\x66\xbb\x10\x76\x46\x37\x75\x98\x4c\x74\x30\x67\xcd\x35\x8f\x6c\xeb\x8e\x1a\x2a\x74\x85\xce\x59\x80\x8b\xeb\x4b\xf8\xd2\x28\xa8\x9a\xd2\x49\xf2\x8b\x98\xde\x73\x81\x95\x56\x76\x04\x5a\x05\x3c\x22\xb2\x82\x25\x06\x7f\x86\x1f\xe1\xb4\x5c\xbd\x38\x44\x0b\xeb\xe3\x76\xbf\xf1\xca\x93\x06\x51\xd7\x46\xd7\x46\x0a\x87\xe5\x89\xec\x79\x31\xbd\x84\x8b\x59\x7e\x10\x2a\xc3\xfc\x12\x6e\x63\x20\xf9\x01\x0b\xf7\x64\x27\x25\x2a\x99\x11\x62\x0c\xa4\x2b\x9d\x93\x66\xcf\x66\x7a\x52\x51\x13\x50\x6b\x65\xd9\x6a\x5e\x5f\x91\x15\xc2\xf3\x9d\xb6\x3a\x0d\x3d\xf8\x5c\x17\x96\x3d\xcf\x78\x04\x2b\x4a\x14\x46\x8d\xa3\x37\x7a\xb6\xd2\xe4\xe6\xfc\x71\x7a\xe5\x5f\x24\x7e\x5e\xeb\x2d\x99\x8f\xbc\x27\x75\xc3\x11\x3f\x78\x8e\xe8\x8f\x93\x5f\x37\xa2\x62\xa4\xe0\xd7\x06\x58\x96\xfb\x1e\x38\x19\x52\x07\xcc\xcd\xfa\x4e\x38\x3c\x0a\x12\xdd\xe8\x66\x57\x74\xd3\xde\x4c\xc4\x61\x01\x91\x5c\xac\xc0\x19\xb1\xa5\xb2\x14\xb3\xe4\x11\x37\xb0\x31\xfa\xe8\xc1\x24\x43\x8e\x88\xee\x4a\xad\xf7\x4d\xcd\x0c\xec\xf4\x53\xd2\x64\xa2\xf5\x33\x04\x10\xb3\xf0\xd9\x50\x72\x39\x5b\x93\x0b\x9a\x33\x94\xf7\xd4\x3b\x22\xa2\xe0\x07\x1e\xd5\x4b\xea\xe3\x72\x34\xed\x14\x98\xd6\xb0\xb8\xe4\x2b\x68\xca\xd3\x65\x9a\xdc\x84\xe2\x1c\x34\x34\x8e\x9a\xc8\x71\x7b\x0d\x9b\x53\x2d\xac\x1d\xe7\x45\x56\x0f\xfe\x83\x95\x04\xc5\xd1\x70\x97\x1a\x90\x62\x5b\x1d\x5b\x8d\x5b\x74\x94\x16\xc9\x95\x42\x13\x49\xe4\xbd\xc0\xc1\x72\x5d\x29\xba\x5b\x3e\x78\x0d\xfc\xba\x78\x19\x35\xdf\xce\xbe\xce\x67\x6b\x8a\xc1\xc2\xb9\xfa\xc7\xab\x2b\x5d\xa3\x3a\xd4\x2a\x55\xe8\xae\xb6\xe2\xcf\xb4\x70\x55\x39\x24\xee\x32\x71\x40\xe1\x6c\x98\x3a\x74\xc8\x62\x83\x54\x06\x0c\x6e\xfd\xf8\x90\xbb\xd4\x66\x53\x72\x3d\xef\xa0\xba\x25\xd5\x1d\x64\x8e\x39\x6c\x4e\x3c\x92\xca\x95\x4d\x33\x5d\xb5\x8a\xa4\x33\xc6\xba\xe6\xca\x4f\xfb\xa6\x93\x77\xe9\x0f\xff\x48\xa7\xd3\x29\xfd\x0d\x92\x97\x57\xf1\x2c\x69\xf9\x00\x7f\xfd\xc5\xda\x7b\x6c\xd3\xf0\x13\x47\x6f\x31\x70\x3f\x99\xf5\x1c\xbd\x37\xde\x18\x58\xc4\x01\x74\x10\x99\x92\xc2\x4f\xa7\xe8\xfb\xa3\xb3\x09\xae\xaf\x5d\x36\x8c\x2e\x5a\x30\x4a\x70\x6c\xab\x4d\x86\xfd\x23\x5e\x58\x3a\x0a\x93\xf7\x73\xe0\xcc\xcc\xf6\xd3\xd2\x59\x7e\x23\x30\xc6\x9b\x5f\xd9\x97\xee\x0b\x42\x59\x71\x7a\x1c\x20\xd0\xdf\x69\x45\x6e\xbb\x94\x1b\x38\x25\x40\x23\x77\x85\x8b\x18\xa7\x6b\x83\xfc\x88\xba\xc3\x50\x57\x7b\x3c\x71\x45\x20\x94\x46\x70\xae\x83\x54\x36\xd6\x79\x9e\x84\xb4\x03\x32\x1e\x14\x95\x7e\x7a\xed\xd0\x32\xde\xac\x1b\x43\xc5\x87\x76\x7c\xd0\xd4\x8e\xe8\xbc\xe1\xeb\x09\x42\x8f\x04\x22\xb1\x37\x89\x0a\x78\x93\xa1\xa6\x24\xfc\x1a\x26\xef\xe7\x1c\xd5\x42\x1a\x3f\x76\x5e\x7c\x80\xdf\xef\x1f\xe1\xe3\xec\xeb\x1c\x96\xf7\x6b\xf8\x79\xbe\x9c\x7f\x99\xad\xe7\x77\xb0\x58\xde\x2d\xbe\x2e\xee\x1e\x67\x9f\x28\xe6\xe6\x5f\xd6\x8b\x0f\x8b\xdb\xd9\x7a\x7e\xf5\xcb\xfc\x77\x58\xcd\x16\x5f\x1e\xe0\xc3\xfd\x17\x98\xcf\x6e\x3f\xc2\xed\xa7\xc5\x7c\xb9\x26\x5e\xf8\xeb\xc7\xd9\xd7\xc5\xf2\x67\x58\xac\x1f\xe0\xfe\xd7\x25\x3c\x2e\x17\xff\xf7\x38\x87\xc1\xed\xfd\xe7\xcf\xf7\x4b\x58\xce\x3e\xcf\x07\xb4\xf6\x71\x49\x4f\xe6\xcb\x35\xac\x3f\x2e\x1e\xe0\xd3\x62\x39\x87\xfb\xc7\x75\x9a\xdc\xe4\x4d\x5d\x32\xbf\xe3\x8c\xaf\x73\x28\x9e\xf6\x88\xb5\x28\xc9\x26\x9d\x75\x28\x85\xa2\x85\x5a\xaa\xdd\xb8\x94\x7b\x9e\x4d\xa0\xb5\x62\x87\xd1\x65\x2d\x29\x85\xdb\x22\xae\x82\xda\xb8\x82\x2f\xdd\x42\xfb\x56\x4a\xb5\x07\xab\x7d\x61\x67\x3d\x72\x93\x49\x2d\x99\xa5\x06\x54\x85\x75\xbe\x13\xe4\x77\x84\x7b\x77\x54\x6c\x73\x7d\x54\xe4\xc9\x2b\x32\x12\x1e\xd0\x9c\xe0\x7a\x02\x16\x33\xad\x72\x3b\x8a\x13\x15\xa6\x6c\xb0\xd2\xdc\x24\xd4\xc8\x6d\xab\x9f\x84\xc9\x2d\x28\xcd\xcc\xc7\xde\x3e\x87\xbc\x31\xa1\x26\xc0\xf5\x34\x52\x03\x27\x2b\x84\x1a\x8d\xd4\x79\x9a\x74\x8a\xb8\x9e\xd0\x22\x52\x10\x39\x06\x7e\x73\x46\xd0\x8e\xc6\x50\xeb\xbe\xc1\x13\x6f\xa5\xf3\x63\x66\xa1\x16\xf1\x14\xef\x81\x46\xbd\xfb\xd4\xc1\xc7\xcf\xb3\xdb\x36\x88\x06\xbe\x31\x2d\xb0\xac\x61\x53\xea\x6c\x0f\x77\xfa\x01\x84\x73\x22\xdb\x5b\x56\xe4\xe3\xdd\x0a\xf8\x42\x78\x5b\x6a\x9d\xfb\x29\x58\x7f\xc8\x7e\x3e\x5b\x3f\xd4\x0a\xc6\xe3\x1d\xaa\x3d\x9e\x60\x3c\xf6\xf3\x7e\x70\x22\x65\x6f\x3c\x9f\xd2\xb6\x17\x26\xc1\xa1\xdb\xab\x24\xd6\x49\xa6\xeb\x93\xbf\x4a\x91\x16\xf6\x78\xea\x46\xbc\xac\xa7\x76\xe4\xdf\xbb\x62\x78\x35\x79\xe5\xc7\xaf\xee\xfc\x90\x57\xd7\xaf\xe2\xd3\x76\xaa\x7b\xe3\x4a\x3b\x16\x0d\x85\x33\x33\x07\x93\xb3\x7b\x0b\x69\xdb\xbb\x8a\x21\x3c\xf0\x7d\x1e\xf1\x64\x4e\xb5\xd3\x3b\x23\xea\x42\x66\x90\xc9\x3a\x64\xc4\x75\xe8\x83\xb6\x72\x07\xd2\x61\xe5\x45\xd9\x50\x67\x55\x4b\xce\x61\xc1\xb9\xe2\x9d\x90\x5f\xca\x27\x71\xf5\x2f\xcb\x34\xb9\xf1\xf4\xe0\xa7\x0f\xe3\xdb\x9f\x6e\x21\xfc\x1b\xc2\x4f\xa5\x3e\x6e\xa5\x2d\xe0\x22\x64\xdd\xcb\x76\xe9\x6c\xfe\x30\xbe\x9e\xbe\x0b\xeb\x87\xf4\xbd\x7d\x77\x37\x7f\x18\xcf\xef\xe6\xaf\xfd\xcb\x21\xac\x0d\x65\xb6\xf1\xdd\xfc\x81\xd1\xbf\x47\xb3\x99\xae\x6a\xbe\x42\xd0\x2a\x6a\x88\x60\x04\xc5\x4a\xef\x72\x3b\x40\x5f\xe9\x78\x8a\xd8\xbb\xbc\xa6\x2c\x4d\x59\xa9\x7d\x2f\xd5\x77\xc4\x4c\x13\x3a\x6a\x5c\xfe\x53\xc7\x20\xaf\xc4\x37\x59\x35\x55\xb8\x8f\x66\x6c\xac\x55\xd6\x18\x2a\x47\xe5\x29\x66\x5c\x76\xe4\xb6\xc8\x60\x8b\xc6\xb9\x7e\xa5\xc9\x4d\x25\xbe\x8d\xe3\xeb\x30\xbf\x5b\xb8\x57\xd4\xae\xec\xb4\xce\x41\xe6\x28\x02\x74\x6b\xb2\xb3\x89\x4b\x32\x0c\x78\xfa\x95\xe5\x56\x4d\x96\x48\xa9\x44\x6c\x79\xda\xa4\xa4\x93\xa2\x94\xff\xe4\xde\xdb\x3b\xfc\xef\xe1\x5e\xbd\x39\xaf\x1f\xd4\xe1\xf0\x34\xee\x85\xcb\xf8\x34\x69\x2c\x89\xe6\xe3\x22\x61\xa8\xdd\x7e\x0b\x6a\x88\x13\x69\x5f\xc6\x43\x21\x75\x86\xe7\x71\xe2\xa0\x65\xde\xb6\x8d\x3c\x90\x08\x80\xc8\xa0\xd5\x8d\xc9\x90\x47\x6b\x61\xbc\xce\x2e\x26\x9c\x07\x7d\x1a\x4a\xad\x76\x68\xb8\x96\xfb\xed\x64\xa2\x0d\x72\x1e\xf5\xbd\x08\xa3\x93\x28\x3a\xe7\xa9\x9d\x11\x39\xa6\x49\xe0\x69\x4c\x31\x1b\x3f\x87\xdb\xf6\xfb\xc6\xd5\x0d\x85\x82\x2d\x28\x27\x58\x27\x5c\xd3\x5d\xf5\x1d\x7d\x42\x0b\x56\x6c\x27\x03\xdc\xb4\x38\xd3\x28\xca\xf3\x11\xdb\x1a\x3c\x1a\xe9\x1c\xaa\x90\x50\x2b\xa9\x1a\x87\x69\x12\x48\x06\x35\x8d\xfd\xd7\xb4\xd4\xbb\xe4\x09\xf4\x28\xf5\xae\x2b\x01\xac\x36\xc2\xc7\x1e\x74\xd9\x93\xa5\xd7\x17\x3a\xdc\xc7\xb4\xbf\x6c\x90\x5b\x30\x8d\x52\x0c\xb3\xad\xbf\x35\x3e\xc8\x0c\xf9\x67\x0c\xa7\x1e\x95\x10\xaf\x83\x3f\x56\x86\xe2\xbd\x82\x0f\x54\xd9\xff\x08\xce\xf3\x47\xa9\x77\xbd\x1b\xe8\xcb\xf8\xa3\x14\x3a\x53\x1b\xfa\x6f\x2c\x6a\x82\x75\x0c\x75\x0e\x68\x0c\x95\x13\x8f\x37\x3c\xfb\xb4\x63\xc0\x54\x82\xc1\xbd\x72\x7c\xa5\xd2\x21\x35\x68\xd5\x01\x7b\xb2\x70\x53\x53\x2d\x3d\x16\xf4\x6e\xd0\x1d\x12\x68\x74\x27\x4a\x97\x02\xf3\xa3\x15\x7a\xc4\xdb\x15\xb6\x8b\x4d\xe3\xfc\x10\x41\xbb\x82\x90\x3b\x9d\x16\xff\x45\xbc\x4b\xda\xbe\xe9\x49\x71\xf6\x82\x13\x22\x37\x41\x7d\x60\x06\x25\x1e\xb0\x24\xb7\xa2\x35\x1e\x09\xc1\x01\xcd\x46\x5b\xe9\x4e\x3e\x84\x26\x9c\x56\x65\x89\xca\x8d\x00\xbf\x65\x58\x3b\x86\x3f\x5b\xe1\x44\x09\x68\x8c\x36\x04\xb9\xde\x78\xa4\x24\xac\xf6\x79\xa5\xbb\xc5\x2f\xa1\x21\x73\x27\x43\x78\xcb\x3e\xf4\x03\x47\x24\x17\x2f\x6a\x45\x71\xd3\xec\x7a\x4e\x47\xb5\x70\x53\x62\x45\x34\xdf\x03\x0f\x5a\x9c\xc1\x8a\x30\xa4\x67\x0c\x13\xfa\x1f\x5e\xb3\x48\xc4\x56\x86\x60\xb0\x46\xff\x6b\x81\xe8\x5b\x29\xc0\xcc\xf9\x1f\xbd\x4c\x27\x0c\x38\xff\x6c\x50\x51\x7e\xe8\xdc\x2f\x44\x13\xa3\xc2\xf0\x90\x5b\x12\x87\x3b\x6d\x4e\xed\xa5\xa1\xf6\xd1\x13\x9c\xb4\xd4\x3b\xca\x60\xfe\x92\x39\xf9\xff\x00\x00\x00\xff\xff\xe2\xd0\xd7\x91\x80\x25\x00\x00") func templateServerConfTmplBytes() ([]byte, error) { return bindataRead( @@ -167,7 +167,7 @@ func templateServerConfTmpl() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "template/server.conf.tmpl", size: 9597, mode: os.FileMode(420), modTime: time.Unix(1504196445, 0)} + info := bindataFileInfo{name: "template/server.conf.tmpl", size: 9600, mode: os.FileMode(420), modTime: time.Unix(1504435146, 0)} a := &asset{bytes: bytes, info: info} return a, nil } diff --git a/cmd/ovpm/vpn.go b/cmd/ovpm/vpn.go index ca131a0..d3f2979 100644 --- a/cmd/ovpm/vpn.go +++ b/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 diff --git a/const.go b/const.go index 58a9019..f26b06a 100644 --- a/const.go +++ b/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/" diff --git a/net_test.go b/net_test.go index 77624ea..a975b40 100644 --- a/net_test.go +++ b/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: diff --git a/pb/vpn.pb.go b/pb/vpn.pb.go index 0cd2d12..4c13dff 100644 --- a/pb/vpn.pb.go +++ b/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, } diff --git a/pb/vpn.proto b/pb/vpn.proto index a3b7467..5beedbf 100644 --- a/pb/vpn.proto +++ b/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 {} diff --git a/pb/vpn.swagger.json b/pb/vpn.swagger.json index 08344d5..20b71e0 100644 --- a/pb/vpn.swagger.json +++ b/pb/vpn.swagger.json @@ -83,6 +83,9 @@ }, "IPBlock": { "type": "string" + }, + "DNS": { + "type": "string" } } }, @@ -133,6 +136,9 @@ }, "Proto": { "type": "string" + }, + "DNS": { + "type": "string" } } } diff --git a/template/server.conf.tmpl b/template/server.conf.tmpl index 85d2984..1610d39 100644 --- a/template/server.conf.tmpl +++ b/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. diff --git a/user_test.go b/user_test.go index fcfe504..912ba3f 100644 --- a/user_test.go +++ b/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: diff --git a/vpn.go b/vpn.go index d3c9b3a..8fb05b4 100644 --- a/vpn.go +++ b/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 { diff --git a/vpn_test.go b/vpn_test.go index a5f7c1b..a28dd3c 100644 --- a/vpn_test.go +++ b/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: From ee18b4cfad0ddbdd765b1f09a68be3a901f3a03b Mon Sep 17 00:00:00 2001 From: Mustafa Arici Date: Sun, 3 Sep 2017 15:09:27 +0300 Subject: [PATCH 08/10] feat(vpn): implement vpn Update --- api/rpc.go | 8 +++ cmd/ovpm/main.go | 1 + cmd/ovpm/vpn.go | 53 ++++++++++++++++++ pb/user.pb.go | 2 + pb/vpn.pb.go | 131 +++++++++++++++++++++++++++++++++----------- pb/vpn.pb.gw.go | 46 ++++++++++++++++ pb/vpn.proto | 13 +++++ pb/vpn.swagger.json | 40 ++++++++++++++ vpn.go | 35 ++++++++++++ 9 files changed, 298 insertions(+), 31 deletions(-) diff --git a/api/rpc.go b/api/rpc.go index 7f29702..9c1101f 100644 --- a/api/rpc.go +++ b/api/rpc.go @@ -210,6 +210,14 @@ func (s *VPNService) Init(ctx context.Context, req *pb.VPNInitRequest) (*pb.VPNI return &pb.VPNInitResponse{}, nil } +func (s *VPNService) Update(ctx context.Context, req *pb.VPNUpdateRequest) (*pb.VPNUpdateResponse, error) { + logrus.Debugf("rpc call: vpn update") + if err := ovpm.Update(req.IPBlock, req.DNS); err != nil { + logrus.Errorf("server can not be updated: %v", err) + } + return &pb.VPNUpdateResponse{}, nil +} + type NetworkService struct{} func (s *NetworkService) List(ctx context.Context, req *pb.NetworkListRequest) (*pb.NetworkListResponse, error) { diff --git a/cmd/ovpm/main.go b/cmd/ovpm/main.go index 36566d0..906021a 100644 --- a/cmd/ovpm/main.go +++ b/cmd/ovpm/main.go @@ -54,6 +54,7 @@ func main() { Subcommands: []cli.Command{ vpnStatusCommand, vpnInitCommand, + vpnUpdateCommand, }, }, { diff --git a/cmd/ovpm/vpn.go b/cmd/ovpm/vpn.go index d3f2979..8a2a609 100644 --- a/cmd/ovpm/vpn.go +++ b/cmd/ovpm/vpn.go @@ -143,3 +143,56 @@ var vpnInitCommand = cli.Command{ return nil }, } + +var vpnUpdateCommand = cli.Command{ + Name: "update", + Usage: "Update VPN server.", + Aliases: []string{"i"}, + Flags: []cli.Flag{ + cli.StringFlag{ + 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:update" + + ipblock := c.String("net") + if ipblock != "" && !govalidator.IsCIDR(ipblock) { + fmt.Println("--net takes an ip network in the CIDR form. e.g. 10.9.0.0/24") + fmt.Println() + fmt.Println(cli.ShowSubcommandHelp(c)) + 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) + } + + if !(ipblock != "" || dns != "") { + fmt.Println() + fmt.Println(cli.ShowSubcommandHelp(c)) + os.Exit(1) + } + + conn := getConn(c.GlobalString("daemon-port")) + defer conn.Close() + vpnSvc := pb.NewVPNServiceClient(conn) + + if _, err := vpnSvc.Update(context.Background(), &pb.VPNUpdateRequest{IPBlock: ipblock, DNS: dns}); err != nil { + logrus.Errorf("server can not be updated: %v", err) + os.Exit(1) + return err + } + logrus.Info("ovpm server updated") + return nil + }, +} diff --git a/pb/user.pb.go b/pb/user.pb.go index 7210f7a..9ddd312 100644 --- a/pb/user.pb.go +++ b/pb/user.pb.go @@ -20,8 +20,10 @@ It has these top-level messages: UserGenConfigResponse VPNStatusRequest VPNInitRequest + VPNUpdateRequest VPNStatusResponse VPNInitResponse + VPNUpdateResponse NetworkCreateRequest NetworkListRequest NetworkDeleteRequest diff --git a/pb/vpn.pb.go b/pb/vpn.pb.go index 4c13dff..cda725f 100644 --- a/pb/vpn.pb.go +++ b/pb/vpn.pb.go @@ -98,6 +98,30 @@ func (m *VPNInitRequest) GetDNS() string { return "" } +type VPNUpdateRequest struct { + IPBlock string `protobuf:"bytes,1,opt,name=IPBlock" json:"IPBlock,omitempty"` + DNS string `protobuf:"bytes,2,opt,name=DNS" json:"DNS,omitempty"` +} + +func (m *VPNUpdateRequest) Reset() { *m = VPNUpdateRequest{} } +func (m *VPNUpdateRequest) String() string { return proto.CompactTextString(m) } +func (*VPNUpdateRequest) ProtoMessage() {} +func (*VPNUpdateRequest) Descriptor() ([]byte, []int) { return fileDescriptor1, []int{2} } + +func (m *VPNUpdateRequest) GetIPBlock() string { + if m != nil { + return m.IPBlock + } + return "" +} + +func (m *VPNUpdateRequest) 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"` @@ -115,7 +139,7 @@ type VPNStatusResponse struct { func (m *VPNStatusResponse) Reset() { *m = VPNStatusResponse{} } func (m *VPNStatusResponse) String() string { return proto.CompactTextString(m) } func (*VPNStatusResponse) ProtoMessage() {} -func (*VPNStatusResponse) Descriptor() ([]byte, []int) { return fileDescriptor1, []int{2} } +func (*VPNStatusResponse) Descriptor() ([]byte, []int) { return fileDescriptor1, []int{3} } func (m *VPNStatusResponse) GetName() string { if m != nil { @@ -200,13 +224,23 @@ type VPNInitResponse struct { func (m *VPNInitResponse) Reset() { *m = VPNInitResponse{} } func (m *VPNInitResponse) String() string { return proto.CompactTextString(m) } func (*VPNInitResponse) ProtoMessage() {} -func (*VPNInitResponse) Descriptor() ([]byte, []int) { return fileDescriptor1, []int{3} } +func (*VPNInitResponse) Descriptor() ([]byte, []int) { return fileDescriptor1, []int{4} } + +type VPNUpdateResponse struct { +} + +func (m *VPNUpdateResponse) Reset() { *m = VPNUpdateResponse{} } +func (m *VPNUpdateResponse) String() string { return proto.CompactTextString(m) } +func (*VPNUpdateResponse) ProtoMessage() {} +func (*VPNUpdateResponse) Descriptor() ([]byte, []int) { return fileDescriptor1, []int{5} } func init() { proto.RegisterType((*VPNStatusRequest)(nil), "pb.VPNStatusRequest") proto.RegisterType((*VPNInitRequest)(nil), "pb.VPNInitRequest") + proto.RegisterType((*VPNUpdateRequest)(nil), "pb.VPNUpdateRequest") proto.RegisterType((*VPNStatusResponse)(nil), "pb.VPNStatusResponse") proto.RegisterType((*VPNInitResponse)(nil), "pb.VPNInitResponse") + proto.RegisterType((*VPNUpdateResponse)(nil), "pb.VPNUpdateResponse") proto.RegisterEnum("pb.VPNProto", VPNProto_name, VPNProto_value) } @@ -223,6 +257,7 @@ const _ = grpc.SupportPackageIsVersion4 type VPNServiceClient interface { Status(ctx context.Context, in *VPNStatusRequest, opts ...grpc.CallOption) (*VPNStatusResponse, error) Init(ctx context.Context, in *VPNInitRequest, opts ...grpc.CallOption) (*VPNInitResponse, error) + Update(ctx context.Context, in *VPNUpdateRequest, opts ...grpc.CallOption) (*VPNUpdateResponse, error) } type vPNServiceClient struct { @@ -251,11 +286,21 @@ func (c *vPNServiceClient) Init(ctx context.Context, in *VPNInitRequest, opts .. return out, nil } +func (c *vPNServiceClient) Update(ctx context.Context, in *VPNUpdateRequest, opts ...grpc.CallOption) (*VPNUpdateResponse, error) { + out := new(VPNUpdateResponse) + err := grpc.Invoke(ctx, "/pb.VPNService/Update", in, out, c.cc, opts...) + if err != nil { + return nil, err + } + return out, nil +} + // Server API for VPNService service type VPNServiceServer interface { Status(context.Context, *VPNStatusRequest) (*VPNStatusResponse, error) Init(context.Context, *VPNInitRequest) (*VPNInitResponse, error) + Update(context.Context, *VPNUpdateRequest) (*VPNUpdateResponse, error) } func RegisterVPNServiceServer(s *grpc.Server, srv VPNServiceServer) { @@ -298,6 +343,24 @@ func _VPNService_Init_Handler(srv interface{}, ctx context.Context, dec func(int return interceptor(ctx, in, info, handler) } +func _VPNService_Update_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(VPNUpdateRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(VPNServiceServer).Update(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/pb.VPNService/Update", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(VPNServiceServer).Update(ctx, req.(*VPNUpdateRequest)) + } + return interceptor(ctx, in, info, handler) +} + var _VPNService_serviceDesc = grpc.ServiceDesc{ ServiceName: "pb.VPNService", HandlerType: (*VPNServiceServer)(nil), @@ -310,6 +373,10 @@ var _VPNService_serviceDesc = grpc.ServiceDesc{ MethodName: "Init", Handler: _VPNService_Init_Handler, }, + { + MethodName: "Update", + Handler: _VPNService_Update_Handler, + }, }, Streams: []grpc.StreamDesc{}, Metadata: "vpn.proto", @@ -318,33 +385,35 @@ var _VPNService_serviceDesc = grpc.ServiceDesc{ func init() { proto.RegisterFile("vpn.proto", fileDescriptor1) } var fileDescriptor1 = []byte{ - // 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, + // 478 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x74, 0x53, 0xcd, 0x6e, 0xd3, 0x40, + 0x10, 0xc6, 0x8e, 0xeb, 0xc6, 0x43, 0x14, 0x9c, 0x49, 0x81, 0x25, 0xea, 0xa1, 0xf2, 0x29, 0xca, + 0x21, 0x16, 0xe5, 0xd6, 0x03, 0x52, 0x49, 0x41, 0xed, 0x01, 0xb3, 0x4a, 0x68, 0xee, 0x9b, 0x76, + 0xa9, 0xac, 0xa6, 0xbb, 0x8b, 0xbd, 0xc9, 0x03, 0xf0, 0x0a, 0xbd, 0xf0, 0x5e, 0xbc, 0x02, 0x4f, + 0xc1, 0x09, 0x79, 0x6c, 0xc7, 0x31, 0x3f, 0xb7, 0x99, 0x6f, 0xfc, 0x7d, 0xfa, 0xe6, 0xdb, 0x31, + 0x04, 0x5b, 0xa3, 0xa6, 0x26, 0xd3, 0x56, 0xa3, 0x6b, 0x56, 0xa3, 0xe3, 0x3b, 0xad, 0xef, 0xd6, + 0x32, 0x16, 0x26, 0x8d, 0x85, 0x52, 0xda, 0x0a, 0x9b, 0x6a, 0x95, 0x97, 0x5f, 0x44, 0x08, 0xe1, + 0x92, 0x27, 0x0b, 0x2b, 0xec, 0x26, 0x9f, 0xcb, 0xaf, 0x1b, 0x99, 0xdb, 0xe8, 0xbb, 0x03, 0xfd, + 0x25, 0x4f, 0xae, 0x54, 0x6a, 0x2b, 0x08, 0x47, 0xd0, 0xbd, 0xd4, 0xb9, 0x55, 0xe2, 0x41, 0x32, + 0xe7, 0xc4, 0x19, 0x07, 0xf3, 0x5d, 0x8f, 0x08, 0x1e, 0xd7, 0x99, 0x65, 0x2e, 0xe1, 0x54, 0xe3, + 0x04, 0x02, 0x5e, 0xe8, 0x9b, 0x4c, 0x7e, 0x61, 0x9d, 0x13, 0x67, 0xdc, 0x3f, 0xed, 0x4d, 0xcd, + 0x6a, 0xba, 0xe4, 0x09, 0xe1, 0xf3, 0x66, 0x8c, 0x0c, 0x0e, 0xaf, 0xf8, 0xbb, 0xb5, 0xbe, 0xb9, + 0x67, 0x1e, 0x49, 0xd4, 0x2d, 0x86, 0xd0, 0xb9, 0x48, 0x16, 0xec, 0x80, 0xd0, 0xa2, 0x8c, 0xde, + 0x92, 0xdd, 0x6b, 0x73, 0x2b, 0xac, 0xac, 0xbd, 0xed, 0xf1, 0x9d, 0x7f, 0xf2, 0xdd, 0x86, 0xff, + 0xe8, 0xc2, 0x60, 0x6f, 0xdf, 0xdc, 0x68, 0x95, 0xd3, 0x06, 0x49, 0xb3, 0x19, 0xd5, 0x18, 0x41, + 0x6f, 0x21, 0xb3, 0x54, 0xac, 0x93, 0xcd, 0xc3, 0x4a, 0x66, 0x95, 0x48, 0x0b, 0x6b, 0xa5, 0xd2, + 0xf9, 0x4f, 0x2a, 0xde, 0x5e, 0x2a, 0x08, 0xde, 0x4c, 0x66, 0xb6, 0x5a, 0x88, 0x6a, 0x7c, 0x01, + 0xfe, 0xec, 0x9c, 0x50, 0x9f, 0xd0, 0xaa, 0x2b, 0xbc, 0x27, 0xd2, 0xb2, 0xc3, 0xd2, 0x7b, 0x22, + 0x89, 0xfd, 0x51, 0xe4, 0xf7, 0xac, 0x5b, 0xb2, 0x8b, 0x1a, 0x8f, 0x21, 0x98, 0x65, 0x52, 0x58, + 0x79, 0x7b, 0x6e, 0x59, 0x40, 0x83, 0x06, 0xc0, 0x23, 0x38, 0xa0, 0x98, 0x19, 0xd0, 0xa4, 0x6c, + 0xea, 0x54, 0x9e, 0x36, 0xa9, 0x0c, 0xe0, 0xd9, 0xee, 0xbd, 0xcb, 0x48, 0xa2, 0x21, 0xe5, 0x54, + 0x07, 0x5d, 0x82, 0x93, 0x31, 0x74, 0xeb, 0x07, 0x44, 0x00, 0x3f, 0xf9, 0xc4, 0xe7, 0xef, 0x3f, + 0x84, 0x4f, 0xf0, 0x10, 0x3a, 0xd7, 0x17, 0x3c, 0x74, 0x8a, 0xe2, 0xf3, 0x8c, 0x87, 0xee, 0xe9, + 0x2f, 0x07, 0xa0, 0xc8, 0x59, 0x66, 0xdb, 0xf4, 0x46, 0x22, 0x07, 0xbf, 0x8c, 0x1c, 0x8f, 0xaa, + 0x2b, 0x68, 0x5d, 0xdc, 0xe8, 0xf9, 0x1f, 0x68, 0x65, 0xe2, 0xd5, 0xb7, 0x1f, 0x3f, 0x1f, 0xdd, + 0x61, 0xd4, 0x8f, 0xb7, 0xaf, 0xe3, 0xad, 0x51, 0x71, 0x4e, 0xf3, 0x33, 0x67, 0x82, 0x97, 0xe0, + 0x15, 0x7e, 0x11, 0x2b, 0xe6, 0xde, 0xb1, 0x8e, 0x86, 0x2d, 0xac, 0xd2, 0x7a, 0x49, 0x5a, 0x83, + 0xa8, 0x57, 0x6b, 0xa5, 0x2a, 0xb5, 0x85, 0x12, 0x07, 0xbf, 0x5c, 0x73, 0xe7, 0xad, 0x75, 0x5e, + 0x3b, 0x6f, 0xed, 0x2c, 0xfe, 0xf6, 0xb6, 0xa1, 0xf9, 0x99, 0x33, 0x59, 0xf9, 0xf4, 0x6b, 0xbd, + 0xf9, 0x1d, 0x00, 0x00, 0xff, 0xff, 0x98, 0x14, 0x2a, 0x0b, 0x89, 0x03, 0x00, 0x00, } diff --git a/pb/vpn.pb.gw.go b/pb/vpn.pb.gw.go index 5910d11..4718248 100644 --- a/pb/vpn.pb.gw.go +++ b/pb/vpn.pb.gw.go @@ -54,6 +54,19 @@ func request_VPNService_Init_0(ctx context.Context, marshaler runtime.Marshaler, } +func request_VPNService_Update_0(ctx context.Context, marshaler runtime.Marshaler, client VPNServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq VPNUpdateRequest + var metadata runtime.ServerMetadata + + if err := marshaler.NewDecoder(req.Body).Decode(&protoReq); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + + msg, err := client.Update(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err + +} + // RegisterVPNServiceHandlerFromEndpoint is same as RegisterVPNServiceHandler but // automatically dials to "endpoint" and closes the connection when "ctx" gets done. func RegisterVPNServiceHandlerFromEndpoint(ctx context.Context, mux *runtime.ServeMux, endpoint string, opts []grpc.DialOption) (err error) { @@ -142,6 +155,35 @@ func RegisterVPNServiceHandler(ctx context.Context, mux *runtime.ServeMux, conn }) + mux.Handle("POST", pattern_VPNService_Update_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(ctx) + defer cancel() + if cn, ok := w.(http.CloseNotifier); ok { + go func(done <-chan struct{}, closed <-chan bool) { + select { + case <-done: + case <-closed: + cancel() + } + }(ctx.Done(), cn.CloseNotify()) + } + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := request_VPNService_Update_0(rctx, inboundMarshaler, client, req, pathParams) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_VPNService_Update_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + return nil } @@ -149,10 +191,14 @@ var ( pattern_VPNService_Status_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"v1", "vpn", "status"}, "")) pattern_VPNService_Init_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"v1", "vpn", "init"}, "")) + + pattern_VPNService_Update_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"v1", "vpn", "update"}, "")) ) var ( forward_VPNService_Status_0 = runtime.ForwardResponseMessage forward_VPNService_Init_0 = runtime.ForwardResponseMessage + + forward_VPNService_Update_0 = runtime.ForwardResponseMessage ) diff --git a/pb/vpn.proto b/pb/vpn.proto index 5beedbf..266603b 100644 --- a/pb/vpn.proto +++ b/pb/vpn.proto @@ -19,6 +19,12 @@ message VPNInitRequest { string DNS = 5; } +message VPNUpdateRequest { + string IPBlock = 1; + string DNS = 2; +} + + service VPNService { rpc Status (VPNStatusRequest) returns (VPNStatusResponse) { option (google.api.http) = { @@ -30,6 +36,12 @@ service VPNService { post: "/v1/vpn/init" body: "*" };} + rpc Update (VPNUpdateRequest) returns (VPNUpdateResponse) { + option (google.api.http) = { + post: "/v1/vpn/update" + body: "*" + };} + } message VPNStatusResponse { @@ -46,3 +58,4 @@ message VPNStatusResponse { string DNS = 11; } message VPNInitResponse {} +message VPNUpdateResponse {} diff --git a/pb/vpn.swagger.json b/pb/vpn.swagger.json index 20b71e0..90a6e33 100644 --- a/pb/vpn.swagger.json +++ b/pb/vpn.swagger.json @@ -66,6 +66,32 @@ "VPNService" ] } + }, + "/v1/vpn/update": { + "post": { + "operationId": "Update", + "responses": { + "200": { + "description": "", + "schema": { + "$ref": "#/definitions/pbVPNUpdateResponse" + } + } + }, + "parameters": [ + { + "name": "body", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/pbVPNUpdateRequest" + } + } + ], + "tags": [ + "VPNService" + ] + } } }, "definitions": { @@ -141,6 +167,20 @@ "type": "string" } } + }, + "pbVPNUpdateRequest": { + "type": "object", + "properties": { + "IPBlock": { + "type": "string" + }, + "DNS": { + "type": "string" + } + } + }, + "pbVPNUpdateResponse": { + "type": "object" } } } diff --git a/vpn.go b/vpn.go index 8fb05b4..e88a7a1 100644 --- a/vpn.go +++ b/vpn.go @@ -276,6 +276,41 @@ func Init(hostname string, port string, proto string, ipblock string, dns string return nil } +// Update updates VPN server attributes. +func Update(ipblock string, dns string) error { + if !IsInitialized() { + return fmt.Errorf("server is not initialized") + } + + server, err := GetServerInstance() + if err != nil { + return err + } + + var changed bool + if ipblock != "" && govalidator.IsCIDR(ipblock) { + var ipnet *net.IPNet + _, ipnet, err = net.ParseCIDR(ipblock) + if err != nil { + return fmt.Errorf("can not parse CIDR %s: %v", ipblock, err) + } + server.dbServerModel.Net = ipnet.IP.To4().String() + server.dbServerModel.Mask = net.IP(ipnet.Mask).To4().String() + changed = true + } + + if dns != "" && govalidator.IsIPv4(dns) { + server.dbServerModel.DNS = dns + changed = true + } + if changed { + db.Save(server.dbServerModel) + Emit() + logrus.Infof("server updated") + } + return nil +} + // Deinit deletes the VPN server from the database and frees the allocated resources. func Deinit() error { if !IsInitialized() { From 27773c98be2b3cc071ce08ed3140feb40ec2beb3 Mon Sep 17 00:00:00 2001 From: Mustafa Arici Date: Sun, 3 Sep 2017 15:33:59 +0300 Subject: [PATCH 09/10] test(vpn): add test case for new vpn update feature --- vpn_test.go | 40 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/vpn_test.go b/vpn_test.go index a28dd3c..b31cb34 100644 --- a/vpn_test.go +++ b/vpn_test.go @@ -106,6 +106,46 @@ func TestVPNDeinit(t *testing.T) { t.Errorf("revoked should be empty") } } +func TestVPNUpdate(t *testing.T) { + // Init: + setupTestCase() + CreateDB("sqlite3", ":memory:") + defer db.Cease() + // Prepare: + Init("localhost", "", UDPProto, "", "") + // Test: + + var updatetests = []struct { + vpnnet string + dns string + vpnChanged bool + dnsChanged bool + }{ + {"", "", false, false}, + {"192.168.9.0/24", "", true, false}, + {"", "2.2.2.2", false, true}, + {"9.9.9.0/24", "1.1.1.1", true, true}, + } + for _, tt := range updatetests { + server, err := GetServerInstance() + if err != nil { + t.Fatal(err) + } + + oldIP := server.Net + oldDNS := server.DNS + Update(tt.vpnnet, tt.dns) + server = nil + server, err = GetServerInstance() + if (server.Net != oldIP) != tt.vpnChanged { + t.Fatalf("expected vpn change: %t but opposite happened", tt.vpnChanged) + } + if (server.DNS != oldDNS) != tt.dnsChanged { + t.Fatalf("expected vpn change: %t but opposite happened", tt.dnsChanged) + } + } + +} func TestVPNIsInitialized(t *testing.T) { // Init: From 558e332412ac4a449a3e321b19837332e64f896e Mon Sep 17 00:00:00 2001 From: Mustafa Arici Date: Sun, 3 Sep 2017 15:41:33 +0300 Subject: [PATCH 10/10] release: v0.1.13 --- CHANGELOG.md | 9 ++++++++- bindata/bindata.go | 2 +- const.go | 2 +- 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 855551d..437eee2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,13 @@ # Change Log -## [v0.1.12](https://github.com/cad/ovpm/tree/v0.1.12) (2017-09-02) +## [v0.1.13](https://github.com/cad/ovpm/tree/v0.1.13) (2017-09-03) +[Full Changelog](https://github.com/cad/ovpm/compare/v0.1.12...v0.1.13) + +**Implemented enhancements:** + +- change dns to push to clients [\#41](https://github.com/cad/ovpm/issues/41) + +## [v0.1.12](https://github.com/cad/ovpm/tree/v0.1.12) (2017-09-01) [Full Changelog](https://github.com/cad/ovpm/compare/v0.1.11...v0.1.12) **Implemented enhancements:** diff --git a/bindata/bindata.go b/bindata/bindata.go index 090a5dc..5ca091c 100644 --- a/bindata/bindata.go +++ b/bindata/bindata.go @@ -167,7 +167,7 @@ func templateServerConfTmpl() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "template/server.conf.tmpl", size: 9600, mode: os.FileMode(420), modTime: time.Unix(1504435146, 0)} + info := bindataFileInfo{name: "template/server.conf.tmpl", size: 9600, mode: os.FileMode(420), modTime: time.Unix(1504442070, 0)} a := &asset{bytes: bytes, info: info} return a, nil } diff --git a/const.go b/const.go index f26b06a..b0a890c 100644 --- a/const.go +++ b/const.go @@ -2,7 +2,7 @@ package ovpm const ( // Version defines the version of ovpm. - Version = "0.1.12" + Version = "0.1.13" // DefaultVPNPort is the default OpenVPN port to listen. DefaultVPNPort = "1197"