Add web login functionality

This commit is contained in:
cyp0633 2024-03-01 23:22:20 +08:00
parent e7e300b338
commit f48aed8a29
8 changed files with 144 additions and 6 deletions

View File

@ -47,7 +47,7 @@ func login() (tail []byte, salt []byte, err error) {
err = ErrorLogin
return
}
util.Logger.Debug("Login result recv", zap.String("packet", hex.EncodeToString(result[:n])))
util.Logger.Debug("Login result recv", zap.String("packet", hex.EncodeToString(result[:n])), zap.Int("len", n))
if bytes.Equal(result[0:1], []byte{0x04}) { // 登录成功
util.Logger.Info("Logged in")
tail = result[23:39] // 同时也是 authinfo
@ -109,9 +109,9 @@ func challenge() (salt []byte, err error) {
err = ErrorChallenge
return
}
util.Logger.Debug("Challenge recv", zap.String("packet", hex.EncodeToString(salt[:n])), zap.String("salt", hex.EncodeToString(salt[4:8])))
util.Logger.Debug("Challenge recv", zap.String("packet", hex.EncodeToString(salt[:n])), zap.Int("len", n), zap.String("salt", hex.EncodeToString(salt[4:8])))
// 长度应为 40 字节
if len(salt) != 40 {
if len(salt) == 106 {
util.Logger.Error("Challenge reply length does not match")
err = ErrorChallenge
return

View File

@ -72,7 +72,7 @@ login:
// 启动连接测试
var ch = make(chan bool, 1)
go util.CheckConnection(ch)
go util.CheckConnection(ch, 5*time.Second)
time.Sleep(3 * time.Second)
// 清除 socket buffer

View File

@ -11,6 +11,7 @@ var CLI struct {
Dhcp struct{} `cmd:"" help:"Use DHCP mode"` // DHCP模式
DhcpAuto struct{} `cmd:"" help:"Use DHCP mode with auto configuration"` // DHCP自动配置模式
Pppoe struct{} `cmd:"" help:"Use PPPoE mode"` // PPPoE模式
Web struct{} `cmd:"" help:"Imitate web login"` // 模拟网页登录
Conf string `help:"Configuration file path" short:"c" default:"/etc/drcom.conf" type:"path"` // 配置文件目录
BindIP string `help:"IP address to bind to" short:"b" default:"0.0.0.0"` // 绑定IP地址
Log string `help:"Log ONLY to specified path" short:"l" default:""` // 日志文件目录

View File

@ -10,7 +10,7 @@ import (
)
// CheckConnection 检查网络连接,如发现不通,向 ch 中发送信号
func CheckConnection(ch chan bool) {
func CheckConnection(ch chan bool, interval time.Duration) {
// 自定义 DNS
resolver := &net.Resolver{
PreferGo: true,
@ -50,7 +50,7 @@ func CheckConnection(ch chan bool) {
} else {
resp.Body.Close()
Logger.Debug("Network connection is OK")
time.Sleep(time.Second * 5)
time.Sleep(interval)
}
}
}

40
internal/web/login.go Normal file
View File

@ -0,0 +1,40 @@
// 用于模拟网页登录
package web
import (
"crypto/md5"
"net/http"
"net/url"
"github.com/cyp0633/drcom-go/internal/util"
"go.uber.org/zap"
)
// 发送登录请求
func doLogin(server_base string) {
username := util.Conf.Username
password := util.Conf.Password
md5Ctx := md5.New()
md5Ctx.Write([]byte("2" + password + "12345678"))
cipherStr := md5Ctx.Sum(nil)
form := url.Values{
"DDDDD": {username},
"upass": {string(cipherStr)},
"0MKKey": {"123456"},
"R1": {"0"},
"R2": {"1"},
"para": {"00"},
"v6ip": {""},
}
util.Logger.Debug("Sending login request", zap.String("server", server_base),zap.String("form",form.Encode()))
response, err := http.PostForm(server_base+"/0.htm", form)
if err != nil {
util.Logger.Error("Send login request failed", zap.Error(err))
}
util.Logger.Info("Login seems successful")
util.Logger.Debug("Response", zap.Any("response", response.Body))
print(response)
defer response.Body.Close()
}

29
internal/web/main.go Normal file
View File

@ -0,0 +1,29 @@
package web
import (
"time"
"github.com/cyp0633/drcom-go/internal/util"
)
// 连接检查与保活
// TODO: 退出时自动注销
func Run() {
var server string
ch := make(chan bool, 1)
go util.CheckConnection(ch, 1*time.Minute) // 似乎比较不容易断,可以设长一点
for {
select {
case <-ch:
util.Logger.Info("Network disconnected, trying to login")
if server == "" {
server = getServer()
}
if server != "" {
doLogin(server)
}
default:
time.Sleep(1 * time.Second)
}
}
}

60
internal/web/server.go Normal file
View File

@ -0,0 +1,60 @@
package web
import (
"io"
"net/http"
"strings"
"github.com/cyp0633/drcom-go/internal/util"
"go.uber.org/zap"
)
// 查找登录服务器地址
func getServer() (server string) {
generate_204 := util.ExtConf.ConnectionTestServer
// 将 HTTPS 改为 HTTP
if generate_204[:5] == "https" {
generate_204 = "http" + generate_204[5:]
}
// 发 GET检查是否有登录信息
response, err := http.Get(generate_204)
if err != nil {
util.Logger.Error("Get server failed", zap.Error(err))
return
}
defer response.Body.Close()
util.Logger.Debug("Find auth server", zap.Any("response", response))
switch response.StatusCode {
case 204: // 正常访问,会返回 204
util.Logger.Warn("204'ed; may be already logged in", zap.Any("response", response))
return
case 302: // 临时重定向Location header 即为认证服务器
server = response.Header.Get("Location")
if server == "" {
util.Logger.Error("Server not found", zap.Any("response", response))
} else {
util.Logger.Info("Auth server found", zap.String("server", server))
}
case 200: // 劫持了内容,但解析似乎没问题
// 截取 location.href="<server>"
bodyBytes, err := io.ReadAll(response.Body)
if err != nil {
util.Logger.Error("Read body failed", zap.Error(err))
return
}
bodyString := string(bodyBytes)
startIndex := strings.Index(bodyString, "location.href=\"")
if startIndex != -1 {
startIndex += len("location.href=\"")
endIndex := strings.Index(bodyString[startIndex:], "\"")
if endIndex != -1 {
server = bodyString[startIndex : startIndex+endIndex]
util.Logger.Info("Auth server found", zap.String("server", server))
}
}
default:
util.Logger.Error("Find auth server: unexpected response", zap.String("state", response.Status))
}
return
}

View File

@ -5,6 +5,7 @@ import (
"github.com/cyp0633/drcom-go/internal/dhcp"
dhcpauto "github.com/cyp0633/drcom-go/internal/dhcp/auto"
"github.com/cyp0633/drcom-go/internal/util"
"github.com/cyp0633/drcom-go/internal/web"
)
func main() {
@ -24,6 +25,13 @@ func main() {
util.Daemonize()
}
dhcp.Run()
case "web":
util.ParseConf()
if util.CLI.Daemon {
util.Logger.Info("Daemon mode")
util.Daemonize()
}
web.Run()
case "pppoe":
util.Logger.Fatal("PPPoE mode not implemented")
}