diff --git a/controllers/extClientHttpController.go b/controllers/extClientHttpController.go index 381e9bae..fde78cb4 100644 --- a/controllers/extClientHttpController.go +++ b/controllers/extClientHttpController.go @@ -9,6 +9,7 @@ import ( "net/http" "strconv" "time" + "github.com/gorilla/mux" "github.com/gravitl/netmaker/database" "github.com/gravitl/netmaker/functions" @@ -91,7 +92,7 @@ func getAllExtClients(w http.ResponseWriter, r *http.Request) { err := errors.New("Networks Error") if networksSlice[0] == ALL_NETWORK_ACCESS { clients, err = functions.GetAllExtClients() - if err != nil && !database.IsEmptyRecord(err){ + if err != nil && !database.IsEmptyRecord(err) { returnErrorResponse(w, r, formatError(err, "internal")) return } @@ -159,14 +160,14 @@ func getExtClientConf(w http.ResponseWriter, r *http.Request) { gwnode, err := functions.GetNodeByMacAddress(client.Network, client.IngressGatewayID) if err != nil { - functions.PrintUserLog(r.Header.Get("user"),"Could not retrieve Ingress Gateway Node " + client.IngressGatewayID,1) + functions.PrintUserLog(r.Header.Get("user"), "Could not retrieve Ingress Gateway Node "+client.IngressGatewayID, 1) returnErrorResponse(w, r, formatError(err, "internal")) return } network, err := functions.GetParentNetwork(client.Network) if err != nil { - functions.PrintUserLog(r.Header.Get("user"),"Could not retrieve Ingress Gateway Network " + client.Network,1) + functions.PrintUserLog(r.Header.Get("user"), "Could not retrieve Ingress Gateway Network "+client.Network, 1) returnErrorResponse(w, r, formatError(err, "internal")) return } @@ -175,6 +176,16 @@ func getExtClientConf(w http.ResponseWriter, r *http.Request) { keepalive = "PersistentKeepalive = " + strconv.Itoa(int(network.DefaultKeepalive)) } gwendpoint := gwnode.Endpoint + ":" + strconv.Itoa(int(gwnode.ListenPort)) + newAllowedIPs := network.AddressRange + if egressGatewayRanges, err := client.GetEgressRangesOnNetwork(); err == nil { + for _, egressGatewayRange := range egressGatewayRanges { + newAllowedIPs += "," + egressGatewayRange + } + } + defaultDNS := "" + if network.DefaultExtClientDNS != "" { + defaultDNS = "DNS = " + network.DefaultExtClientDNS + } config := fmt.Sprintf(`[Interface] Address = %s PrivateKey = %s @@ -184,13 +195,15 @@ PublicKey = %s AllowedIPs = %s Endpoint = %s %s +%s `, client.Address+"/32", client.PrivateKey, gwnode.PublicKey, - network.AddressRange, + newAllowedIPs, gwendpoint, - keepalive) + keepalive, + defaultDNS) if params["type"] == "qr" { bytes, err := qrcode.Encode(config, qrcode.Medium, 220) @@ -219,7 +232,7 @@ Endpoint = %s } return } - functions.PrintUserLog(r.Header.Get("user"),"retrieved ext client config",2) + functions.PrintUserLog(r.Header.Get("user"), "retrieved ext client config", 2) w.WriteHeader(http.StatusOK) json.NewEncoder(w).Encode(client) } @@ -263,6 +276,7 @@ func CreateExtClient(extclient models.ExtClient) error { err = SetNetworkNodesLastModified(extclient.Network) return err } + /** * To create a extclient * Must have valid key and be unique @@ -289,7 +303,6 @@ func createExtClient(w http.ResponseWriter, r *http.Request) { return } extclient.IngressGatewayEndpoint = node.Endpoint + ":" + strconv.FormatInt(int64(node.ListenPort), 10) - err = json.NewDecoder(r.Body).Decode(&extclient) if err != nil && !errors.Is(err, io.EOF) { returnErrorResponse(w, r, formatError(err, "internal")) diff --git a/docs/external-clients.rst b/docs/external-clients.rst index 66eddcae..bd525061 100644 --- a/docs/external-clients.rst +++ b/docs/external-clients.rst @@ -57,3 +57,16 @@ Example config file: .. literalinclude:: ./examplecode/myclient.conf Your client should now be able to access the network! A client can be invalidated at any time by simply deleting it from the UI. + +Configuring DNS for Ext Clients (OPTIONAL) +============================================ + +If you wish to have a DNS field on your ext clients conf, simply edit the network field as shown below to 1.1.1.1 or 8.8.8.8 for example. +If you do not want DNS on your ext client conf files, simply leave it blank. + +.. image:: images/exclient5.png + :width: 80% + :alt: Gateway + :align: center + +Important to note, your client automatically adds egress gateway ranges (if any on the same network) to it's allowed IPs. diff --git a/docs/images/extclient5.png b/docs/images/extclient5.png new file mode 100644 index 00000000..dba775c8 Binary files /dev/null and b/docs/images/extclient5.png differ diff --git a/models/extclient.go b/models/extclient.go index 5932f7f6..d88991ff 100644 --- a/models/extclient.go +++ b/models/extclient.go @@ -1,13 +1,48 @@ package models +import ( + "encoding/json" + + "github.com/gravitl/netmaker/database" +) + type ExtClient struct { - ClientID string `json:"clientid" bson:"clientid"` - Description string `json:"description" bson:"description"` - PrivateKey string `json:"privatekey" bson:"privatekey"` - PublicKey string `json:"publickey" bson:"publickey"` - Network string `json:"network" bson:"network"` - Address string `json:"address" bson:"address"` - LastModified int64 `json:"lastmodified" bson:"lastmodified"` - IngressGatewayID string `json:"ingressgatewayid" bson:"ingressgatewayid"` - IngressGatewayEndpoint string `json:"ingressgatewayendpoint" bson:"ingressgatewayendpoint"` + ClientID string `json:"clientid" bson:"clientid"` + Description string `json:"description" bson:"description"` + PrivateKey string `json:"privatekey" bson:"privatekey"` + PublicKey string `json:"publickey" bson:"publickey"` + Network string `json:"network" bson:"network"` + Address string `json:"address" bson:"address"` + IngressGatewayID string `json:"ingressgatewayid" bson:"ingressgatewayid"` + IngressGatewayEndpoint string `json:"ingressgatewayendpoint" bson:"ingressgatewayendpoint"` + LastModified int64 `json:"lastmodified" bson:"lastmodified"` +} + +/** + * Get the egress gateway ips of a given ExtClient struct + * returns as []string + */ +func (client *ExtClient) GetEgressRangesOnNetwork() ([]string, error) { + + var result []string + nodesData, err := database.FetchRecords(database.NODES_TABLE_NAME) + if err != nil { + return []string{}, err + } + for _, nodeData := range nodesData { + var currentNode Node + if err = json.Unmarshal([]byte(nodeData), ¤tNode); err != nil { + continue + } + if currentNode.Network != client.Network { + continue + } + if currentNode.IsEgressGateway == "yes" { // add the egress gateway range(s) to the result + if len(currentNode.EgressGatewayRanges) > 0 { + result = append(result, currentNode.EgressGatewayRanges...) + } + } + } + + return result, nil } diff --git a/models/network.go b/models/network.go index 2e8da3fe..f6c0e458 100644 --- a/models/network.go +++ b/models/network.go @@ -7,9 +7,10 @@ import ( "reflect" "strings" "time" - "github.com/gravitl/netmaker/servercfg" + "github.com/go-playground/validator/v10" "github.com/gravitl/netmaker/database" + "github.com/gravitl/netmaker/servercfg" ) //Network Struct @@ -39,6 +40,7 @@ type Network struct { LocalRange string `json:"localrange" bson:"localrange" validate:"omitempty,cidr"` DefaultCheckInInterval int32 `json:"checkininterval,omitempty" bson:"checkininterval,omitempty" validate:"omitempty,numeric,min=2,max=100000"` DefaultUDPHolePunch string `json:"defaultudpholepunch" bson:"defaultudpholepunch" validate:"checkyesorno"` + DefaultExtClientDNS string `json:"defaultextclientdns" bson:"defaultextclientdns"` } type SaveData struct { // put sensitive fields here diff --git a/netclient/netclient32 b/netclient/netclient32 new file mode 100755 index 00000000..212721b5 Binary files /dev/null and b/netclient/netclient32 differ diff --git a/netmaker32 b/netmaker32 new file mode 100755 index 00000000..f2af4c9a Binary files /dev/null and b/netmaker32 differ diff --git a/test/nodecreate.sh b/test/nodecreate.sh index 517dc09e..795264e6 100755 --- a/test/nodecreate.sh +++ b/test/nodecreate.sh @@ -1,9 +1,9 @@ #!/bin/bash -PUBKEY="DM5qhLAE20PG9BbfBCger+Ac9D2NDOwCtY1rbYDLf34=" -IPADDR="69.173.21.202" -MACADDRESS="59:2a:9c:d4:e2:49" -ACCESSKEY="6Cc1m3x0B0LQhHWF" +PUBKEY="DM5qhLAE20EG9BbfBEger+Ac9D2NDOwCtY1rbYDLf34=" +IPADDR="70.173.21.212" +MACADDRESS="59:23:9c:f2:e4:49" +ACCESSKEY="Gsl6FKOjWi2qPGXy" PASSWORD="ppppppp" generate_post_json () @@ -15,7 +15,7 @@ generate_post_json () "macaddress": "$MACADDRESS", "password": "$PASSWORD", "localaddress": "172.123.123.3", - "accesskey": "zKfzHn9W6uL5KuIg" + "accesskey": "$ACCESSKEY" } EOF }