package openp2p import ( "bytes" "encoding/binary" "encoding/json" "hash/crc64" "math/big" "net" "time" ) const OpenP2PVersion = "3.5.0" const ProducnName string = "openp2p" const LeastSupportVersion = "3.0.0" const ( IfconfigPort1 = 27180 IfconfigPort2 = 27181 WsPort = 27183 UDPPort1 = 27182 UDPPort2 = 27183 ) type openP2PHeader struct { DataLen uint32 MainType uint16 SubType uint16 } var openP2PHeaderSize = binary.Size(openP2PHeader{}) type PushHeader struct { From uint64 To uint64 } var PushHeaderSize = binary.Size(PushHeader{}) type overlayHeader struct { id uint64 } var overlayHeaderSize = binary.Size(overlayHeader{}) func decodeHeader(data []byte) (*openP2PHeader, error) { head := openP2PHeader{} rd := bytes.NewReader(data) err := binary.Read(rd, binary.LittleEndian, &head) if err != nil { return nil, err } return &head, nil } func encodeHeader(mainType uint16, subType uint16, len uint32) []byte { head := openP2PHeader{ len, mainType, subType, } headBuf := new(bytes.Buffer) err := binary.Write(headBuf, binary.LittleEndian, head) if err != nil { return []byte("") } return headBuf.Bytes() } // Message type const ( MsgLogin = 0 MsgHeartbeat = 1 MsgNATDetect = 2 MsgPush = 3 MsgP2P = 4 MsgRelay = 5 MsgReport = 6 MsgQuery = 7 ) // TODO: seperate node push and web push. const ( MsgPushRsp = 0 MsgPushConnectReq = 1 MsgPushConnectRsp = 2 MsgPushHandshakeStart = 3 MsgPushAddRelayTunnelReq = 4 MsgPushAddRelayTunnelRsp = 5 MsgPushUpdate = 6 MsgPushReportApps = 7 MsgPushUnderlayConnect = 8 MsgPushEditApp = 9 MsgPushSwitchApp = 10 MsgPushRestart = 11 MsgPushEditNode = 12 MsgPushAPPKey = 13 MsgPushReportLog = 14 ) // MsgP2P sub type message const ( MsgPunchHandshake = iota MsgPunchHandshakeAck MsgTunnelHandshake MsgTunnelHandshakeAck MsgTunnelHeartbeat MsgTunnelHeartbeatAck MsgOverlayConnectReq MsgOverlayConnectRsp MsgOverlayDisconnectReq MsgOverlayData MsgRelayData MsgRelayHeartbeat MsgRelayHeartbeatAck ) // MsgRelay sub type message const ( MsgRelayNodeReq = iota MsgRelayNodeRsp ) // MsgReport sub type message const ( MsgReportBasic = iota MsgReportQuery MsgReportConnect MsgReportApps MsgReportLog ) const ( ReadBuffLen = 4096 // for UDP maybe not enough NetworkHeartbeatTime = time.Second * 30 // TODO: server no response hb, save flow TunnelHeartbeatTime = time.Second * 15 TunnelIdleTimeout = time.Minute SymmetricHandshakeNum = 800 // 0.992379 // SymmetricHandshakeNum = 1000 // 0.999510 SymmetricHandshakeInterval = time.Millisecond SymmetricHandshakeAckTimeout = time.Second * 11 PeerAddRelayTimeount = time.Second * 20 CheckActiveTimeout = time.Second * 5 PaddingSize = 16 AESKeySize = 16 MaxRetry = 10 RetryInterval = time.Second * 30 PublicIPEchoTimeout = time.Second * 1 NatTestTimeout = time.Second * 10 ClientAPITimeout = time.Second * 10 MaxDirectTry = 3 ) // NATNone has public ip const ( NATNone = 0 NATCone = 1 NATSymmetric = 2 NATUnknown = 314 ) // underlay protocol const ( UderlayAuto = "auto" UderlayQUIC = "quic" UderlayTCP = "tcp" ) // linkmode const ( LinkModeUDPPunch = "udppunch" LinkModeTCPPunch = "tcppunch" LinkModeIPv4 = "ipv4" // for web LinkModeIPv6 = "ipv6" // for web LinkModeTCP6 = "tcp6" LinkModeTCP4 = "tcp4" LinkModeUDP6 = "udp6" LinkModeUDP4 = "udp4" ) const ( MsgQueryPeerInfoReq = iota MsgQueryPeerInfoRsp ) func newMessage(mainType uint16, subType uint16, packet interface{}) ([]byte, error) { data, err := json.Marshal(packet) if err != nil { return nil, err } // gLog.Println(LevelINFO,"write packet:", string(data)) head := openP2PHeader{ uint32(len(data)), mainType, subType, } headBuf := new(bytes.Buffer) err = binary.Write(headBuf, binary.LittleEndian, head) if err != nil { return nil, err } writeBytes := append(headBuf.Bytes(), data...) return writeBytes, nil } func nodeNameToID(name string) uint64 { return crc64.Checksum([]byte(name), crc64.MakeTable(crc64.ISO)) } type PushConnectReq struct { From string `json:"from,omitempty"` FromToken uint64 `json:"fromToken,omitempty"` // deprecated Version string `json:"version,omitempty"` Token uint64 `json:"token,omitempty"` // if public totp token ConeNatPort int `json:"coneNatPort,omitempty"` // if isPublic, is public port NatType int `json:"natType,omitempty"` HasIPv4 int `json:"hasIPv4,omitempty"` IPv6 string `json:"IPv6,omitempty"` HasUPNPorNATPMP int `json:"hasUPNPorNATPMP,omitempty"` FromIP string `json:"fromIP,omitempty"` ID uint64 `json:"id,omitempty"` AppKey uint64 `json:"appKey,omitempty"` // for underlay tcp LinkMode string `json:"linkMode,omitempty"` IsUnderlayServer int `json:"isServer,omitempty"` // Requset spec peer is server } type PushConnectRsp struct { Error int `json:"error,omitempty"` From string `json:"from,omitempty"` To string `json:"to,omitempty"` Detail string `json:"detail,omitempty"` NatType int `json:"natType,omitempty"` HasIPv4 int `json:"hasIPv4,omitempty"` IPv6 string `json:"IPv6,omitempty"` // if public relay node, ipv6 not set HasUPNPorNATPMP int `json:"hasUPNPorNATPMP,omitempty"` ConeNatPort int `json:"coneNatPort,omitempty"` //it's not only cone, but also upnp or nat-pmp hole FromIP string `json:"fromIP,omitempty"` ID uint64 `json:"id,omitempty"` Version string `json:"version,omitempty"` } type PushRsp struct { Error int `json:"error,omitempty"` Detail string `json:"detail,omitempty"` } type LoginRsp struct { Error int `json:"error,omitempty"` Detail string `json:"detail,omitempty"` User string `json:"user,omitempty"` Node string `json:"node,omitempty"` Token uint64 `json:"token,omitempty"` Ts int64 `json:"ts,omitempty"` } type NatDetectReq struct { SrcPort int `json:"srcPort,omitempty"` EchoPort int `json:"echoPort,omitempty"` } type NatDetectRsp struct { IP string `json:"IP,omitempty"` Port int `json:"port,omitempty"` IsPublicIP int `json:"isPublicIP,omitempty"` } type P2PHandshakeReq struct { ID uint64 `json:"id,omitempty"` } type OverlayConnectReq struct { ID uint64 `json:"id,omitempty"` Token uint64 `json:"token,omitempty"` // not totp token DstIP string `json:"dstIP,omitempty"` DstPort int `json:"dstPort,omitempty"` Protocol string `json:"protocol,omitempty"` RelayTunnelID uint64 `json:"relayTunnelID,omitempty"` // if not 0 relay AppID uint64 `json:"appID,omitempty"` } type OverlayDisconnectReq struct { ID uint64 `json:"id,omitempty"` } type TunnelMsg struct { ID uint64 `json:"id,omitempty"` } type RelayNodeReq struct { PeerNode string `json:"peerNode,omitempty"` } type RelayNodeRsp struct { Mode string `json:"mode,omitempty"` // private,public RelayName string `json:"relayName,omitempty"` RelayToken uint64 `json:"relayToken,omitempty"` } type AddRelayTunnelReq struct { From string `json:"from,omitempty"` RelayName string `json:"relayName,omitempty"` RelayToken uint64 `json:"relayToken,omitempty"` AppID uint64 `json:"appID,omitempty"` // deprecated AppKey uint64 `json:"appKey,omitempty"` // deprecated } type APPKeySync struct { AppID uint64 `json:"appID,omitempty"` AppKey uint64 `json:"appKey,omitempty"` } type RelayHeartbeat struct { RelayTunnelID uint64 `json:"relayTunnelID,omitempty"` AppID uint64 `json:"appID,omitempty"` } type ReportBasic struct { OS string `json:"os,omitempty"` Mac string `json:"mac,omitempty"` LanIP string `json:"lanIP,omitempty"` HasIPv4 int `json:"hasIPv4,omitempty"` IPv6 string `json:"IPv6,omitempty"` HasUPNPorNATPMP int `json:"hasUPNPorNATPMP,omitempty"` Version string `json:"version,omitempty"` NetInfo NetInfo `json:"netInfo,omitempty"` } type ReportConnect struct { Error string `json:"error,omitempty"` Protocol string `json:"protocol,omitempty"` SrcPort int `json:"srcPort,omitempty"` NatType int `json:"natType,omitempty"` PeerNode string `json:"peerNode,omitempty"` DstPort int `json:"dstPort,omitempty"` DstHost string `json:"dstHost,omitempty"` PeerUser string `json:"peerUser,omitempty"` PeerNatType int `json:"peerNatType,omitempty"` PeerIP string `json:"peerIP,omitempty"` ShareBandwidth int `json:"shareBandWidth,omitempty"` RelayNode string `json:"relayNode,omitempty"` Version string `json:"version,omitempty"` } type AppInfo struct { AppName string `json:"appName,omitempty"` Error string `json:"error,omitempty"` Protocol string `json:"protocol,omitempty"` SrcPort int `json:"srcPort,omitempty"` Protocol0 string `json:"protocol0,omitempty"` SrcPort0 int `json:"srcPort0,omitempty"` NatType int `json:"natType,omitempty"` PeerNode string `json:"peerNode,omitempty"` DstPort int `json:"dstPort,omitempty"` DstHost string `json:"dstHost,omitempty"` PeerUser string `json:"peerUser,omitempty"` PeerNatType int `json:"peerNatType,omitempty"` PeerIP string `json:"peerIP,omitempty"` ShareBandwidth int `json:"shareBandWidth,omitempty"` RelayNode string `json:"relayNode,omitempty"` RelayMode string `json:"relayMode,omitempty"` LinkMode string `json:"linkMode,omitempty"` Version string `json:"version,omitempty"` RetryTime string `json:"retryTime,omitempty"` ConnectTime string `json:"connectTime,omitempty"` IsActive int `json:"isActive,omitempty"` Enabled int `json:"enabled,omitempty"` } type ReportApps struct { Apps []AppInfo } type ReportLogReq struct { FileName string `json:"fileName,omitempty"` Offset int64 `json:"offset,omitempty"` Len int64 `json:"len,omitempty"` } type ReportLogRsp struct { FileName string `json:"fileName,omitempty"` Content string `json:"content,omitempty"` Len int64 `json:"len,omitempty"` Total int64 `json:"total,omitempty"` } type UpdateInfo struct { Error int `json:"error,omitempty"` ErrorDetail string `json:"errorDetail,omitempty"` Url string `json:"url,omitempty"` } type NetInfo struct { IP net.IP `json:"ip"` IPDecimal *big.Int `json:"ip_decimal"` Country string `json:"country,omitempty"` CountryISO string `json:"country_iso,omitempty"` CountryEU *bool `json:"country_eu,omitempty"` RegionName string `json:"region_name,omitempty"` RegionCode string `json:"region_code,omitempty"` MetroCode uint `json:"metro_code,omitempty"` PostalCode string `json:"zip_code,omitempty"` City string `json:"city,omitempty"` Latitude float64 `json:"latitude,omitempty"` Longitude float64 `json:"longitude,omitempty"` Timezone string `json:"time_zone,omitempty"` ASN string `json:"asn,omitempty"` ASNOrg string `json:"asn_org,omitempty"` Hostname string `json:"hostname,omitempty"` } type ProfileInfo struct { User string `json:"user,omitempty"` Password string `json:"password,omitempty"` Email string `json:"email,omitempty"` Phone string `json:"phone,omitempty"` Token string `json:"token,omitempty"` Addtime string `json:"addtime,omitempty"` } type EditNode struct { NewName string `json:"newName,omitempty"` Bandwidth int `json:"bandwidth,omitempty"` } type QueryPeerInfoReq struct { Token uint64 `json:"token,omitempty"` // if public totp token PeerNode string `json:"peerNode,omitempty"` } type QueryPeerInfoRsp struct { Online int `json:"online,omitempty"` Version string `json:"version,omitempty"` NatType int `json:"natType,omitempty"` IPv4 string `json:"IPv4,omitempty"` HasIPv4 int `json:"hasIPv4,omitempty"` // has public ipv4 IPv6 string `json:"IPv6,omitempty"` // if public relay node, ipv6 not set HasUPNPorNATPMP int `json:"hasUPNPorNATPMP,omitempty"` }