mirror of
https://github.com/fumiama/go-nd-portal.git
synced 2026-07-02 00:50:25 +08:00
refactor: auto get client ip from challenge response (#5)
* refactor: auto get client ip from challenge response Since `outip()` was not working properly on devices getting local IP addresses behind a router, we should refactor this. After analyzing the auth process, it is shown that the challenge response includes key `client_ip` which is the real public IP address with key `ip` not specified in request. - removed `outip()` - added rsp key `ClientIP` to get client ip from challenge rsp * style: trim code * style: fix spelling issues * refactor: create `portal_test.go` to handle portal tests separately * feature: add `ResolveLocalClientIP()` and its test case * optimize: resolve ClientIP locally when cant be get from challenge response
This commit is contained in:
@@ -8,6 +8,7 @@ import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"net"
|
||||
"net/netip"
|
||||
"time"
|
||||
|
||||
"github.com/sirupsen/logrus"
|
||||
@@ -16,12 +17,12 @@ import (
|
||||
)
|
||||
|
||||
var (
|
||||
// ErrIllegalIPv4 is returned when an invalid IPv4 address is provided
|
||||
ErrIllegalIPv4 = errors.New("illegal ipv4")
|
||||
// ErrIllegalLoginType is returned when an invalid login type is provided
|
||||
ErrIllegalLoginType = errors.New("illegal login type")
|
||||
// ErrUnexpectedChallengeResponse is returned when challenge is shorter than expected
|
||||
ErrUnexpectedChallengeResponse = errors.New("unexpected challenge response")
|
||||
// ErrCannotDetermineClientIP is returned when client IP cant get from challenge or local resolution with cip not specified
|
||||
ErrCannotDetermineClientIP = errors.New("failed to determine client IP from challenge response or local resolution")
|
||||
// ErrUnexpectedLoginResponse is returned when login resp is shorter than expected
|
||||
ErrUnexpectedLoginResponse = errors.New("unexpected login response")
|
||||
)
|
||||
@@ -30,7 +31,7 @@ var (
|
||||
type Portal struct {
|
||||
name string
|
||||
pswd string
|
||||
cip net.IP
|
||||
cip string
|
||||
sip string
|
||||
domain string
|
||||
acid string
|
||||
@@ -89,18 +90,26 @@ func (lt LoginType) ToDomainAcID() (string, string, error) {
|
||||
return domain, acid, nil
|
||||
}
|
||||
|
||||
// ResolveLocalClientIP resolves Client IP locally
|
||||
func ResolveLocalClientIP() (string, error) {
|
||||
conn, err := net.Dial("udp", "8.8.8.8:53")
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
defer conn.Close()
|
||||
|
||||
return conn.LocalAddr().(*net.UDPAddr).IP.String(), nil
|
||||
}
|
||||
|
||||
// rsp struct for converting from raw response data to JSON
|
||||
type rsp struct {
|
||||
ClientIP string `json:"client_ip"`
|
||||
Challenge string `json:"challenge"`
|
||||
Error string `json:"error"`
|
||||
}
|
||||
|
||||
// NewPortal creates a new Portal instance
|
||||
func NewPortal(name, password, sIP string, cIP net.IP, loginType LoginType) (*Portal, error) {
|
||||
if len(cIP) != 4 {
|
||||
return nil, ErrIllegalIPv4
|
||||
}
|
||||
|
||||
func NewPortal(name, password, sIP string, cIP string, loginType LoginType) (*Portal, error) {
|
||||
domain, acid, err := loginType.ToDomainAcID()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -157,6 +166,22 @@ func (p *Portal) GetChallenge() (string, error) {
|
||||
if r.Error != "ok" {
|
||||
return "", errors.New(r.Error)
|
||||
}
|
||||
// if cip was left empty, try get from challenge resp
|
||||
if p.cip == "" {
|
||||
logrus.Debugln("client ip is not specified, try get client ip from challenge resp")
|
||||
_, err = netip.ParseAddr(r.ClientIP)
|
||||
if err == nil {
|
||||
p.cip = r.ClientIP
|
||||
logrus.Debugln("get client ip from challenge resp:", r.ClientIP)
|
||||
} else {
|
||||
// if ClientIP is invalid, try resolve it locally
|
||||
p.cip, err = ResolveLocalClientIP()
|
||||
if err != nil {
|
||||
return "", ErrCannotDetermineClientIP
|
||||
}
|
||||
logrus.Debugln("failed to get client ip from challenge resp, using locally resolved ip:", p.cip)
|
||||
}
|
||||
}
|
||||
logrus.Debugln("get challenge:", r.Challenge)
|
||||
return r.Challenge, nil
|
||||
}
|
||||
@@ -211,6 +236,11 @@ func (p *Portal) Login(challenge string) error {
|
||||
return err
|
||||
}
|
||||
logrus.Debugln("login rsp:", &r)
|
||||
// compare local cip with response client_ip
|
||||
if p.cip != r.ClientIP {
|
||||
logrus.Warnln("client ip in login request does not match response! unexpected errors may occur")
|
||||
logrus.Warnf("request: %s, response: %s", p.cip, r.ClientIP)
|
||||
}
|
||||
if r.Error != "ok" {
|
||||
return errors.New(r.Error)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user