mirror of
https://github.com/KusakabeShi/EtherGuard-VPN.git
synced 2024-11-07 16:04:00 +01:00
792 lines
23 KiB
Go
792 lines
23 KiB
Go
/* SPDX-License-Identifier: MIT
|
|
*
|
|
* Copyright (C) 2017-2021 Kusakabe Si. All Rights Reserved.
|
|
*/
|
|
|
|
package main
|
|
|
|
import (
|
|
"crypto/md5"
|
|
"crypto/sha256"
|
|
"encoding/base64"
|
|
"encoding/hex"
|
|
"encoding/json"
|
|
"fmt"
|
|
"io/ioutil"
|
|
"net"
|
|
"strconv"
|
|
"strings"
|
|
"sync"
|
|
"sync/atomic"
|
|
"time"
|
|
|
|
"net/http"
|
|
"net/url"
|
|
|
|
"github.com/golang-jwt/jwt"
|
|
"golang.org/x/crypto/sha3"
|
|
|
|
"github.com/KusakabeSi/EtherGuard-VPN/device"
|
|
"github.com/KusakabeSi/EtherGuard-VPN/mtypes"
|
|
"github.com/KusakabeSi/EtherGuard-VPN/path"
|
|
yaml "gopkg.in/yaml.v2"
|
|
)
|
|
|
|
type http_shared_objects struct {
|
|
http_graph *path.IG
|
|
http_device4 *device.Device
|
|
http_device6 *device.Device
|
|
http_HashSalt []byte
|
|
http_NhTable_Hash string
|
|
http_PeerInfo_hash string
|
|
http_NhTableStr []byte
|
|
http_PeerInfo mtypes.API_Peers
|
|
http_super_chains *mtypes.SUPER_Events
|
|
|
|
http_passwords mtypes.Passwords
|
|
http_StateExpire time.Time
|
|
http_StateString_tmp []byte
|
|
|
|
http_PeerID2Info map[mtypes.Vertex]mtypes.SuperPeerInfo
|
|
http_PeerState map[string]*PeerState //the state hash reported by peer
|
|
http_PeerIPs map[string]*HttpPeerLocalIP
|
|
|
|
http_sconfig *mtypes.SuperConfig
|
|
|
|
http_sconfig_path string
|
|
http_econfig_tmp *mtypes.EdgeConfig
|
|
|
|
sync.RWMutex
|
|
}
|
|
|
|
var (
|
|
httpobj http_shared_objects
|
|
)
|
|
|
|
type HttpPeerLocalIP struct {
|
|
LocalIPv4 map[string]float64
|
|
LocalIPv6 map[string]float64
|
|
}
|
|
|
|
type HttpState struct {
|
|
PeerInfo map[mtypes.Vertex]HttpPeerInfo
|
|
Infinity float64
|
|
Edges map[mtypes.Vertex]map[mtypes.Vertex]float64
|
|
Edges_Nh map[mtypes.Vertex]map[mtypes.Vertex]float64
|
|
NhTable mtypes.NextHopTable
|
|
Dist mtypes.DistTable
|
|
}
|
|
|
|
type HttpPeerInfo struct {
|
|
Name string
|
|
LastSeen string
|
|
}
|
|
|
|
type PeerState struct {
|
|
NhTableState atomic.Value // string
|
|
PeerInfoState atomic.Value // string
|
|
SuperParamState atomic.Value // string
|
|
SuperParamStateClient atomic.Value // string
|
|
JETSecret atomic.Value // mtypes.JWTSecret
|
|
httpPostCount atomic.Value // uint64
|
|
LastSeen atomic.Value // time.Time
|
|
}
|
|
|
|
type client struct {
|
|
ConnV4 net.Addr
|
|
ConnV6 net.Addr
|
|
InterV4 []net.Addr
|
|
InterV6 []net.Addr
|
|
notify4 string
|
|
notify6 string
|
|
}
|
|
|
|
func extractParamsStr(params url.Values, key string, w http.ResponseWriter) (string, error) {
|
|
valA, has := params[key]
|
|
if !has {
|
|
errstr := fmt.Sprintf("Paramater %v: Missing paramater.", key)
|
|
if w != nil {
|
|
w.WriteHeader(http.StatusBadRequest)
|
|
w.Write([]byte(errstr))
|
|
}
|
|
return "", fmt.Errorf(errstr)
|
|
}
|
|
return valA[0], nil
|
|
}
|
|
|
|
func extractParamsFloat(params url.Values, key string, bitSize int, w http.ResponseWriter) (float64, error) {
|
|
val, err := extractParamsStr(params, key, w)
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
ret, err := strconv.ParseFloat(val, 64)
|
|
if err != nil {
|
|
errstr := fmt.Sprintf("Paramater %v: Can't convert to type float%v", key, bitSize)
|
|
if w != nil {
|
|
w.WriteHeader(http.StatusBadRequest)
|
|
w.Write([]byte(errstr))
|
|
}
|
|
return 0, fmt.Errorf(errstr)
|
|
}
|
|
return ret, nil
|
|
}
|
|
|
|
func extractParamsUint(params url.Values, key string, bitSize int, w http.ResponseWriter) (uint64, error) {
|
|
val, err := extractParamsStr(params, key, w)
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
ret, err := strconv.ParseUint(val, 10, bitSize)
|
|
if err != nil {
|
|
errstr := fmt.Sprintf("Paramater %v: Can't convert to type uint%v", key, bitSize)
|
|
if w != nil {
|
|
w.WriteHeader(http.StatusBadRequest)
|
|
w.Write([]byte(errstr))
|
|
}
|
|
return 0, fmt.Errorf(errstr)
|
|
}
|
|
return ret, nil
|
|
}
|
|
|
|
func extractParamsVertex(params url.Values, key string, w http.ResponseWriter) (mtypes.Vertex, error) {
|
|
val, err := extractParamsUint(params, key, 16, w)
|
|
if err != nil {
|
|
return mtypes.BrokenMessage, err
|
|
}
|
|
return mtypes.Vertex(val), nil
|
|
}
|
|
|
|
func get_api_peers(old_State_hash string) (api_peerinfo mtypes.API_Peers, StateHash string, changed bool) {
|
|
// No lock
|
|
api_peerinfo = make(mtypes.API_Peers)
|
|
for _, peerinfo := range httpobj.http_sconfig.Peers {
|
|
api_peerinfo[peerinfo.PubKey] = mtypes.API_Peerinfo{
|
|
NodeID: peerinfo.NodeID,
|
|
PSKey: peerinfo.PSKey,
|
|
Connurl: &mtypes.API_connurl{},
|
|
}
|
|
if httpobj.http_PeerState[peerinfo.PubKey].LastSeen.Load().(time.Time).Add(mtypes.S2TD(httpobj.http_sconfig.PeerAliveTimeout)).After(time.Now()) {
|
|
connV4 := httpobj.http_device4.GetConnurl(peerinfo.NodeID)
|
|
connV6 := httpobj.http_device6.GetConnurl(peerinfo.NodeID)
|
|
if connV4 != "" {
|
|
api_peerinfo[peerinfo.PubKey].Connurl.ExternalV4 = map[string]float64{connV4: 4}
|
|
}
|
|
if connV6 != "" {
|
|
api_peerinfo[peerinfo.PubKey].Connurl.ExternalV6 = map[string]float64{connV6: 6}
|
|
}
|
|
if !peerinfo.SkipLocalIP {
|
|
api_peerinfo[peerinfo.PubKey].Connurl.LocalV4 = httpobj.http_PeerIPs[peerinfo.PubKey].LocalIPv4
|
|
api_peerinfo[peerinfo.PubKey].Connurl.LocalV6 = httpobj.http_PeerIPs[peerinfo.PubKey].LocalIPv6
|
|
}
|
|
}
|
|
|
|
}
|
|
api_peerinfo_str_byte, _ := json.Marshal(&api_peerinfo)
|
|
hash_raw := md5.Sum(append(api_peerinfo_str_byte, httpobj.http_HashSalt...))
|
|
hash_str := hex.EncodeToString(hash_raw[:])
|
|
StateHash = hash_str
|
|
if old_State_hash != StateHash {
|
|
changed = true
|
|
}
|
|
return
|
|
}
|
|
|
|
func get_superparams(w http.ResponseWriter, r *http.Request) {
|
|
// Read all params
|
|
params := r.URL.Query()
|
|
PubKey, err := extractParamsStr(params, "PubKey", w)
|
|
if err != nil {
|
|
return
|
|
}
|
|
State, err := extractParamsStr(params, "State", w)
|
|
if err != nil {
|
|
return
|
|
}
|
|
NodeID, err := extractParamsVertex(params, "NodeID", w)
|
|
if err != nil {
|
|
return
|
|
}
|
|
if NodeID >= mtypes.Special_NodeID {
|
|
w.WriteHeader(http.StatusBadRequest)
|
|
w.Write([]byte("Paramater NodeID: Can't use special nodeID."))
|
|
return
|
|
}
|
|
// Authentication
|
|
httpobj.RLock()
|
|
defer httpobj.RUnlock()
|
|
if _, has := httpobj.http_PeerID2Info[NodeID]; !has {
|
|
w.WriteHeader(http.StatusNotFound)
|
|
w.Write([]byte("Paramater PubKey: NodeID and PubKey are not match"))
|
|
return
|
|
}
|
|
if httpobj.http_PeerID2Info[NodeID].PubKey != PubKey {
|
|
w.WriteHeader(http.StatusNotFound)
|
|
w.Write([]byte("Paramater PubKey: NodeID and PubKey are not match"))
|
|
return
|
|
}
|
|
|
|
if _, has := httpobj.http_PeerState[PubKey]; has == false {
|
|
w.WriteHeader(http.StatusInternalServerError)
|
|
w.Write([]byte("Paramater PubKey: Not found in httpobj.http_PeerState, this shouldn't happen. Please report to the author."))
|
|
return
|
|
}
|
|
|
|
if httpobj.http_PeerState[PubKey].SuperParamState.Load().(string) != State {
|
|
w.WriteHeader(http.StatusNotFound)
|
|
w.Write([]byte("Paramater State: State not correct"))
|
|
return
|
|
}
|
|
// Do something
|
|
SuperParams := mtypes.API_SuperParams{
|
|
SendPingInterval: httpobj.http_sconfig.SendPingInterval,
|
|
HttpPostInterval: httpobj.http_sconfig.HttpPostInterval,
|
|
PeerAliveTimeout: httpobj.http_sconfig.PeerAliveTimeout,
|
|
AdditionalCost: httpobj.http_PeerID2Info[NodeID].AdditionalCost,
|
|
}
|
|
SuperParamStr, _ := json.Marshal(SuperParams)
|
|
httpobj.http_PeerState[PubKey].SuperParamStateClient.Store(State)
|
|
w.Header().Set("Content-Type", "application/json")
|
|
w.WriteHeader(http.StatusOK)
|
|
w.Write([]byte(SuperParamStr))
|
|
return
|
|
}
|
|
|
|
func get_peerinfo(w http.ResponseWriter, r *http.Request) {
|
|
// Read all params
|
|
params := r.URL.Query()
|
|
PubKey, err := extractParamsStr(params, "PubKey", w)
|
|
if err != nil {
|
|
return
|
|
}
|
|
State, err := extractParamsStr(params, "State", w)
|
|
if err != nil {
|
|
return
|
|
}
|
|
NodeID, err := extractParamsVertex(params, "NodeID", w)
|
|
if err != nil {
|
|
return
|
|
}
|
|
if NodeID >= mtypes.Special_NodeID {
|
|
w.WriteHeader(http.StatusBadRequest)
|
|
w.Write([]byte("Paramater NodeID: Can't use special nodeID."))
|
|
return
|
|
}
|
|
// Authentication
|
|
httpobj.RLock()
|
|
defer httpobj.RUnlock()
|
|
if _, has := httpobj.http_PeerID2Info[NodeID]; !has {
|
|
w.WriteHeader(http.StatusNotFound)
|
|
w.Write([]byte("Paramater PubKey: NodeID and PubKey are not match"))
|
|
return
|
|
}
|
|
if httpobj.http_PeerID2Info[NodeID].PubKey != PubKey {
|
|
w.WriteHeader(http.StatusNotFound)
|
|
w.Write([]byte("Paramater PubKey: NodeID and PubKey are not match"))
|
|
return
|
|
}
|
|
if httpobj.http_PeerInfo_hash != State {
|
|
w.WriteHeader(http.StatusNotFound)
|
|
w.Write([]byte("Paramater State: State not correct"))
|
|
return
|
|
}
|
|
if _, has := httpobj.http_PeerState[PubKey]; has == false {
|
|
w.WriteHeader(http.StatusInternalServerError)
|
|
w.Write([]byte("Paramater PubKey: Not found in httpobj.http_PeerState, this shouldn't happen. Please report to the author."))
|
|
return
|
|
}
|
|
|
|
// Do something
|
|
httpobj.http_PeerState[PubKey].PeerInfoState.Store(State)
|
|
http_PeerInfo_2peer := make(mtypes.API_Peers)
|
|
|
|
for PeerPubKey, peerinfo := range httpobj.http_PeerInfo {
|
|
if httpobj.http_sconfig.UsePSKForInterEdge {
|
|
h := sha256.New()
|
|
if NodeID > peerinfo.NodeID {
|
|
h.Write([]byte(PubKey))
|
|
h.Write([]byte(PeerPubKey))
|
|
} else if NodeID < peerinfo.NodeID {
|
|
h.Write([]byte(PeerPubKey))
|
|
h.Write([]byte(PubKey))
|
|
} else {
|
|
continue
|
|
}
|
|
h.Write(httpobj.http_HashSalt)
|
|
bs := h.Sum(nil)
|
|
var psk device.NoisePresharedKey
|
|
copy(psk[:], bs[:])
|
|
peerinfo.PSKey = psk.ToString()
|
|
} else {
|
|
peerinfo.PSKey = ""
|
|
}
|
|
if httpobj.http_PeerID2Info[NodeID].SkipLocalIP { // Clear all local IP
|
|
peerinfo.Connurl.LocalV4 = make(map[string]float64)
|
|
peerinfo.Connurl.LocalV6 = make(map[string]float64)
|
|
}
|
|
http_PeerInfo_2peer[PeerPubKey] = peerinfo
|
|
}
|
|
api_peerinfo_str_byte, _ := json.Marshal(&http_PeerInfo_2peer)
|
|
|
|
w.Header().Set("Content-Type", "application/json")
|
|
w.WriteHeader(http.StatusOK)
|
|
w.Write(api_peerinfo_str_byte)
|
|
return
|
|
}
|
|
|
|
func get_nhtable(w http.ResponseWriter, r *http.Request) {
|
|
// Read all params
|
|
params := r.URL.Query()
|
|
PubKey, err := extractParamsStr(params, "PubKey", w)
|
|
if err != nil {
|
|
return
|
|
}
|
|
State, err := extractParamsStr(params, "State", w)
|
|
if err != nil {
|
|
return
|
|
}
|
|
NodeID, err := extractParamsVertex(params, "NodeID", w)
|
|
if err != nil {
|
|
return
|
|
}
|
|
if NodeID >= mtypes.Special_NodeID {
|
|
w.WriteHeader(http.StatusBadRequest)
|
|
w.Write([]byte("Paramater NodeID: Can't use special nodeID."))
|
|
return
|
|
}
|
|
// Authentication
|
|
httpobj.RLock()
|
|
defer httpobj.RUnlock()
|
|
if _, has := httpobj.http_PeerID2Info[NodeID]; !has {
|
|
w.WriteHeader(http.StatusNotFound)
|
|
w.Write([]byte("Paramater PubKey: NodeID and PubKey are not match"))
|
|
return
|
|
}
|
|
if httpobj.http_PeerID2Info[NodeID].PubKey != PubKey {
|
|
w.WriteHeader(http.StatusNotFound)
|
|
w.Write([]byte("Paramater PubKey: NodeID and PubKey are not match"))
|
|
return
|
|
}
|
|
if httpobj.http_NhTable_Hash != State {
|
|
w.WriteHeader(http.StatusNotFound)
|
|
w.Write([]byte("Paramater State: State not correct"))
|
|
return
|
|
}
|
|
if _, has := httpobj.http_PeerState[PubKey]; has == false {
|
|
w.WriteHeader(http.StatusInternalServerError)
|
|
w.Write([]byte("Paramater PubKey: Not found in httpobj.http_PeerState, this shouldn't happen. Please report to the author."))
|
|
return
|
|
}
|
|
|
|
httpobj.http_PeerState[PubKey].NhTableState.Store(State)
|
|
w.Header().Set("Content-Type", "application/json")
|
|
w.WriteHeader(http.StatusOK)
|
|
w.Write([]byte(httpobj.http_NhTableStr))
|
|
return
|
|
|
|
}
|
|
|
|
func get_peerstate(w http.ResponseWriter, r *http.Request) {
|
|
params := r.URL.Query()
|
|
password, err := extractParamsStr(params, "Password", w)
|
|
if err != nil {
|
|
return
|
|
}
|
|
if password != httpobj.http_passwords.ShowState {
|
|
w.WriteHeader(http.StatusUnauthorized)
|
|
w.Write([]byte("Wrong password"))
|
|
return
|
|
}
|
|
httpobj.RLock()
|
|
defer httpobj.RUnlock()
|
|
if time.Now().After(httpobj.http_StateExpire) {
|
|
hs := HttpState{
|
|
PeerInfo: make(map[mtypes.Vertex]HttpPeerInfo),
|
|
NhTable: httpobj.http_graph.GetNHTable(false),
|
|
Infinity: path.Infinity,
|
|
Edges: httpobj.http_graph.GetEdges(false, false),
|
|
Edges_Nh: httpobj.http_graph.GetEdges(true, true),
|
|
Dist: httpobj.http_graph.GetDtst(),
|
|
}
|
|
|
|
for _, peerinfo := range httpobj.http_sconfig.Peers {
|
|
LastSeenStr := httpobj.http_PeerState[peerinfo.PubKey].LastSeen.Load().(time.Time).String()
|
|
hs.PeerInfo[peerinfo.NodeID] = HttpPeerInfo{
|
|
Name: peerinfo.Name,
|
|
LastSeen: LastSeenStr,
|
|
}
|
|
}
|
|
httpobj.http_StateExpire = time.Now().Add(5 * time.Second)
|
|
httpobj.http_StateString_tmp, _ = json.Marshal(hs)
|
|
}
|
|
w.WriteHeader(http.StatusOK)
|
|
w.Write(httpobj.http_StateString_tmp)
|
|
return
|
|
}
|
|
|
|
func post_nodeinfo(w http.ResponseWriter, r *http.Request) {
|
|
params := r.URL.Query()
|
|
|
|
NodeID, err := extractParamsVertex(params, "NodeID", w)
|
|
if err != nil {
|
|
return
|
|
}
|
|
PubKey, err := extractParamsStr(params, "PubKey", w)
|
|
if err != nil {
|
|
return
|
|
}
|
|
if NodeID >= mtypes.Special_NodeID {
|
|
w.WriteHeader(http.StatusBadRequest)
|
|
w.Write([]byte("Paramater NodeID: Can't use special nodeID."))
|
|
return
|
|
}
|
|
|
|
JWTSig, err := extractParamsStr(params, "JWTSig", w)
|
|
if err != nil {
|
|
return
|
|
}
|
|
|
|
httpobj.RLock()
|
|
defer httpobj.RUnlock()
|
|
if _, has := httpobj.http_PeerID2Info[NodeID]; !has {
|
|
w.WriteHeader(http.StatusNotFound)
|
|
w.Write([]byte("NodeID and PunKey are not match"))
|
|
return
|
|
}
|
|
if httpobj.http_PeerID2Info[NodeID].PubKey != PubKey {
|
|
w.WriteHeader(http.StatusNotFound)
|
|
w.Write([]byte("NodeID and PunKey are not match"))
|
|
return
|
|
}
|
|
|
|
JWTSecret := httpobj.http_PeerState[PubKey].JETSecret
|
|
httpPostCount := httpobj.http_PeerState[PubKey].httpPostCount
|
|
|
|
client_body, err := ioutil.ReadAll(r.Body)
|
|
if err != nil {
|
|
w.WriteHeader(http.StatusBadRequest)
|
|
w.Write([]byte(fmt.Sprintf("Request body: Error reading request body: %v", err)))
|
|
return
|
|
}
|
|
|
|
token_claims := mtypes.API_report_peerinfo_jwt_claims{}
|
|
|
|
token, err := jwt.ParseWithClaims(string(JWTSig), &token_claims, func(token *jwt.Token) (interface{}, error) {
|
|
// Don't forget to validate the alg is what you expect:
|
|
if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok {
|
|
return nil, fmt.Errorf("Unexpected signing method: %v", token.Header["alg"])
|
|
}
|
|
JWTSecretB := JWTSecret.Load().(mtypes.JWTSecret)
|
|
return JWTSecretB[:], nil
|
|
})
|
|
if err != nil {
|
|
w.WriteHeader(http.StatusBadRequest)
|
|
w.Write([]byte(fmt.Sprintf("Paramater JWTSig: Signature verification failed: %v", err)))
|
|
return
|
|
}
|
|
if !token.Valid {
|
|
w.WriteHeader(http.StatusBadRequest)
|
|
w.Write([]byte(fmt.Sprintf("Paramater JWTSig: Signature verification failed: Invalid token")))
|
|
return
|
|
}
|
|
|
|
client_PostCount := token_claims.PostCount
|
|
client_body_hash := token_claims.BodyHash
|
|
|
|
if client_PostCount < httpPostCount.Load().(uint64) {
|
|
w.WriteHeader(http.StatusBadRequest)
|
|
w.Write([]byte(fmt.Sprintf("Request body: postcount too small: %v", httpPostCount)))
|
|
return
|
|
}
|
|
|
|
calculated_body_hash := sha3.Sum512(client_body)
|
|
if base64.StdEncoding.EncodeToString(calculated_body_hash[:]) == client_body_hash {
|
|
w.WriteHeader(http.StatusBadRequest)
|
|
w.Write([]byte(fmt.Sprintf("Request body: hash not match: %v", client_body_hash)))
|
|
return
|
|
}
|
|
|
|
client_body, err = mtypes.GUzip(client_body)
|
|
if err != nil {
|
|
w.WriteHeader(http.StatusBadRequest)
|
|
w.Write([]byte(fmt.Sprintf("Request body: gzip unzip failed")))
|
|
return
|
|
}
|
|
client_report, err := mtypes.ParseAPI_report_peerinfo(client_body)
|
|
if err != nil {
|
|
w.WriteHeader(http.StatusBadRequest)
|
|
w.Write([]byte(fmt.Sprintf("Request body: Error parsing request body: %v", err)))
|
|
return
|
|
}
|
|
|
|
httpobj.http_PeerIPs[PubKey].LocalIPv4 = client_report.LocalV4s
|
|
httpobj.http_PeerIPs[PubKey].LocalIPv6 = client_report.LocalV6s
|
|
httpobj.http_PeerState[PubKey].httpPostCount.Store(client_PostCount + 1)
|
|
|
|
applied_pones := make([]mtypes.PongMsg, 0, len(client_report.Pongs))
|
|
for _, pong_msg := range client_report.Pongs {
|
|
if pong_msg.Src_nodeID != NodeID {
|
|
continue
|
|
}
|
|
|
|
if info, has := httpobj.http_PeerID2Info[pong_msg.Dst_nodeID]; !has {
|
|
AdditionalCost_use := info.AdditionalCost
|
|
|
|
if AdditionalCost_use >= 0 {
|
|
pong_msg.AdditionalCost = AdditionalCost_use
|
|
}
|
|
applied_pones = append(applied_pones, pong_msg)
|
|
}
|
|
}
|
|
changed := httpobj.http_graph.UpdateLatencyMulti(client_report.Pongs, true, true)
|
|
if changed {
|
|
NhTable := httpobj.http_graph.GetNHTable(true)
|
|
NhTablestr, _ := json.Marshal(NhTable)
|
|
md5_hash_raw := md5.Sum(append(NhTablestr, httpobj.http_HashSalt...))
|
|
new_hash_str := hex.EncodeToString(md5_hash_raw[:])
|
|
httpobj.http_NhTable_Hash = new_hash_str
|
|
httpobj.http_NhTableStr = NhTablestr
|
|
PushNhTable(false)
|
|
}
|
|
w.WriteHeader(http.StatusOK)
|
|
w.Write([]byte(fmt.Sprintf("OK")))
|
|
return
|
|
}
|
|
|
|
func peeradd(w http.ResponseWriter, r *http.Request) { //Waiting for test
|
|
params := r.URL.Query()
|
|
password, err := extractParamsStr(params, "Password", w)
|
|
if err != nil {
|
|
return
|
|
}
|
|
if password != httpobj.http_passwords.AddPeer {
|
|
w.WriteHeader(http.StatusUnauthorized)
|
|
w.Write([]byte("Wrong password"))
|
|
return
|
|
}
|
|
|
|
r.ParseForm()
|
|
NodeID, err := extractParamsVertex(r.Form, "NodeID", w)
|
|
if err != nil {
|
|
return
|
|
}
|
|
Name, err := extractParamsStr(r.Form, "Name", w)
|
|
if err != nil {
|
|
return
|
|
}
|
|
|
|
AdditionalCost, err := extractParamsFloat(r.Form, "AdditionalCost", 64, w)
|
|
if err != nil {
|
|
return
|
|
}
|
|
|
|
PubKey, err := extractParamsStr(r.Form, "PubKey", w)
|
|
if err != nil {
|
|
return
|
|
}
|
|
|
|
SkipLocalIPS, err := extractParamsStr(r.Form, "SkipLocalIP", w)
|
|
if err != nil {
|
|
return
|
|
}
|
|
|
|
SkipLocalIP := strings.EqualFold(SkipLocalIPS, "true")
|
|
|
|
PSKey, err := extractParamsStr(r.Form, "PSKey", nil)
|
|
|
|
httpobj.Lock()
|
|
defer httpobj.Unlock()
|
|
|
|
for _, peerinfo := range httpobj.http_sconfig.Peers {
|
|
if peerinfo.NodeID == NodeID {
|
|
w.WriteHeader(http.StatusConflict)
|
|
w.Write([]byte("Paramater NodeID: NodeID exists"))
|
|
return
|
|
}
|
|
if peerinfo.Name == Name {
|
|
w.WriteHeader(http.StatusConflict)
|
|
w.Write([]byte("Paramater Name: Node name exists"))
|
|
return
|
|
}
|
|
if peerinfo.PubKey == PubKey {
|
|
w.WriteHeader(http.StatusConflict)
|
|
w.Write([]byte("Paramater PubKey: PubKey exists"))
|
|
return
|
|
}
|
|
}
|
|
if httpobj.http_sconfig.GraphRecalculateSetting.StaticMode == true {
|
|
NhTableStr := r.Form.Get("NextHopTable")
|
|
if NhTableStr == "" {
|
|
w.WriteHeader(http.StatusExpectationFailed)
|
|
w.Write([]byte("Paramater NextHopTable: Your NextHopTable is in static mode.\nPlease provide your new NextHopTable in \"NextHopTable\" parmater in json format"))
|
|
return
|
|
}
|
|
var NewNhTable mtypes.NextHopTable
|
|
err := json.Unmarshal([]byte(NhTableStr), &NewNhTable)
|
|
if err != nil {
|
|
w.WriteHeader(http.StatusExpectationFailed)
|
|
w.Write([]byte(fmt.Sprintf("Paramater NextHopTable: \"%v\", %v", NhTableStr, err)))
|
|
return
|
|
}
|
|
err = checkNhTable(NewNhTable, append(httpobj.http_sconfig.Peers, mtypes.SuperPeerInfo{
|
|
NodeID: NodeID,
|
|
Name: Name,
|
|
PubKey: PubKey,
|
|
PSKey: PSKey,
|
|
AdditionalCost: AdditionalCost,
|
|
SkipLocalIP: SkipLocalIP,
|
|
}))
|
|
if err != nil {
|
|
w.WriteHeader(http.StatusExpectationFailed)
|
|
w.Write([]byte(fmt.Sprintf("Paramater nexthoptable: \"%v\", %v", NhTableStr, err)))
|
|
return
|
|
}
|
|
httpobj.http_graph.SetNHTable(NewNhTable)
|
|
}
|
|
err = super_peeradd(mtypes.SuperPeerInfo{
|
|
NodeID: NodeID,
|
|
Name: Name,
|
|
PubKey: PubKey,
|
|
PSKey: PSKey,
|
|
AdditionalCost: AdditionalCost,
|
|
SkipLocalIP: SkipLocalIP,
|
|
})
|
|
if err != nil {
|
|
w.WriteHeader(http.StatusExpectationFailed)
|
|
w.Write([]byte(fmt.Sprintf("Error creating peer: %v", err)))
|
|
return
|
|
}
|
|
httpobj.http_sconfig.Peers = append(httpobj.http_sconfig.Peers, mtypes.SuperPeerInfo{
|
|
NodeID: NodeID,
|
|
Name: Name,
|
|
PubKey: PubKey,
|
|
PSKey: PSKey,
|
|
AdditionalCost: AdditionalCost,
|
|
SkipLocalIP: SkipLocalIP,
|
|
})
|
|
mtypesBytes, _ := yaml.Marshal(httpobj.http_sconfig)
|
|
ioutil.WriteFile(httpobj.http_sconfig_path, mtypesBytes, 0644)
|
|
httpobj.http_econfig_tmp.NodeID = NodeID
|
|
httpobj.http_econfig_tmp.NodeName = Name
|
|
httpobj.http_econfig_tmp.PrivKey = "Your_Private_Key"
|
|
httpobj.http_econfig_tmp.DynamicRoute.SuperNode.PSKey = PSKey
|
|
httpobj.http_econfig_tmp.DynamicRoute.AdditionalCost = AdditionalCost
|
|
httpobj.http_econfig_tmp.DynamicRoute.SuperNode.SkipLocalIP = SkipLocalIP
|
|
ret_str_byte, _ := yaml.Marshal(&httpobj.http_econfig_tmp)
|
|
w.WriteHeader(http.StatusOK)
|
|
w.Write(ret_str_byte)
|
|
return
|
|
}
|
|
|
|
func peerdel(w http.ResponseWriter, r *http.Request) { //Waiting for test
|
|
params := r.URL.Query()
|
|
toDelete := mtypes.Broadcast
|
|
|
|
var err error
|
|
var NodeID mtypes.Vertex
|
|
var PrivKey string
|
|
var PubKey string
|
|
password, pwderr := extractParamsStr(params, "Password", nil)
|
|
httpobj.Lock()
|
|
defer httpobj.Unlock()
|
|
if pwderr == nil { // user provide the password
|
|
if password == httpobj.http_passwords.DelPeer {
|
|
NodeID, err = extractParamsVertex(params, "NodeID", w)
|
|
if err != nil {
|
|
return
|
|
}
|
|
toDelete = NodeID
|
|
if _, has := httpobj.http_PeerID2Info[toDelete]; !has {
|
|
w.WriteHeader(http.StatusNotFound)
|
|
w.Write([]byte(fmt.Sprintf("Paramater NodeID: \"%v\" not found", PubKey)))
|
|
return
|
|
}
|
|
} else {
|
|
w.WriteHeader(http.StatusUnauthorized)
|
|
w.Write([]byte("Paramater Password: Wrong password"))
|
|
return
|
|
}
|
|
} else { // user don't provide the password
|
|
PrivKey, err = extractParamsStr(params, "PrivKey", w)
|
|
if err != nil {
|
|
return
|
|
}
|
|
privk, err := device.Str2PriKey(PrivKey)
|
|
if err != nil {
|
|
w.WriteHeader(http.StatusInternalServerError)
|
|
w.Write([]byte(fmt.Sprintf("Paramater PrivKey: %v", err)))
|
|
return
|
|
}
|
|
pubk := privk.PublicKey()
|
|
PubKey = pubk.ToString()
|
|
for _, peerinfo := range httpobj.http_sconfig.Peers {
|
|
if peerinfo.PubKey == PubKey {
|
|
toDelete = peerinfo.NodeID
|
|
}
|
|
}
|
|
if toDelete == mtypes.Broadcast {
|
|
w.WriteHeader(http.StatusNotFound)
|
|
w.Write([]byte(fmt.Sprintf("Paramater PrivKey: \"%v\" not found", PubKey)))
|
|
return
|
|
}
|
|
}
|
|
|
|
var peers_new []mtypes.SuperPeerInfo
|
|
for _, peerinfo := range httpobj.http_sconfig.Peers {
|
|
if peerinfo.NodeID == toDelete {
|
|
super_peerdel(peerinfo.NodeID)
|
|
} else {
|
|
peers_new = append(peers_new, peerinfo)
|
|
}
|
|
}
|
|
|
|
httpobj.http_sconfig.Peers = peers_new
|
|
mtypesBytes, _ := yaml.Marshal(httpobj.http_sconfig)
|
|
ioutil.WriteFile(httpobj.http_sconfig_path, mtypesBytes, 0644)
|
|
w.WriteHeader(http.StatusOK)
|
|
w.Write([]byte("NodeID: " + toDelete.ToString() + " deleted."))
|
|
return
|
|
}
|
|
|
|
func HttpServer(edgeListen string, manageListen string, apiprefix string) (err error) {
|
|
if len(apiprefix) > 0 && apiprefix[0] != '/' {
|
|
apiprefix = "/" + apiprefix
|
|
}
|
|
if len(edgeListen) > 0 && edgeListen[0] != ':' {
|
|
edgeListen = ":" + edgeListen
|
|
}
|
|
if len(manageListen) > 0 && manageListen[0] != ':' {
|
|
manageListen = ":" + manageListen
|
|
}
|
|
if edgeListen == manageListen {
|
|
mux := http.NewServeMux()
|
|
mux.HandleFunc(apiprefix+"/edge/superparams", get_superparams)
|
|
mux.HandleFunc(apiprefix+"/edge/peerinfo", get_peerinfo)
|
|
mux.HandleFunc(apiprefix+"/edge/nhtable", get_nhtable)
|
|
mux.HandleFunc(apiprefix+"/edge/post/nodeinfo", post_nodeinfo)
|
|
mux.HandleFunc(apiprefix+"/manage/peerstate", get_peerstate)
|
|
mux.HandleFunc(apiprefix+"/manage/peer/add", peeradd)
|
|
mux.HandleFunc(apiprefix+"/manage/peer/del", peerdel)
|
|
err = http.ListenAndServe(edgeListen, mux)
|
|
return
|
|
} else {
|
|
edgemux := http.NewServeMux()
|
|
managemux := http.NewServeMux()
|
|
edgemux.HandleFunc(apiprefix+"/edge/superparams", get_superparams)
|
|
edgemux.HandleFunc(apiprefix+"/edge/peerinfo", get_peerinfo)
|
|
edgemux.HandleFunc(apiprefix+"/edge/nhtable", get_nhtable)
|
|
edgemux.HandleFunc(apiprefix+"/edge/post/nodeinfo", post_nodeinfo)
|
|
managemux.HandleFunc(apiprefix+"/manage/peerstate", get_peerstate)
|
|
managemux.HandleFunc(apiprefix+"/manage/peer/add", peeradd)
|
|
managemux.HandleFunc(apiprefix+"/manage/peer/del", peerdel)
|
|
err = http.ListenAndServe(edgeListen, edgemux)
|
|
if err != nil {
|
|
return
|
|
}
|
|
if manageListen != "" {
|
|
err = http.ListenAndServe(manageListen, managemux)
|
|
}
|
|
return
|
|
}
|
|
|
|
}
|