modemkicker: init

This commit is contained in:
Serge Bazanski 2026-03-29 18:01:29 +02:00
commit ee874b28ad
4 changed files with 824 additions and 0 deletions

143
main.go Normal file
View file

@ -0,0 +1,143 @@
package main
import (
"context"
"crypto/rand"
"encoding/base64"
"flag"
"fmt"
"io"
"log"
"net/http"
"net/http/cookiejar"
"net/url"
"strings"
)
var (
flagAddress string
flagUsername string
flagPassword string
)
const (
sessionKey = "SESSION_ID_VIGOR"
)
func makeAddress(page string) string {
u, err := url.Parse(flagAddress)
if err != nil {
panic(fmt.Sprintf("Invalid address (%q): %v", flagAddress, err))
}
u = u.JoinPath(page)
return u.String()
}
type client struct {
random string
jar *cookiejar.Jar
}
func (c *client) doRequest(ctx context.Context, body io.Reader, method, url, referer string) (*http.Response, error) {
req, err := http.NewRequestWithContext(ctx, method, url, body)
if err != nil {
return nil, err
}
req.Header.Add("Content-Type", "application/x-www-form-urlencoded")
req.Header.Add("Referer", referer)
req.Header.Add("Origin", makeAddress(""))
client := &http.Client{
Jar: c.jar,
}
return client.Do(req)
}
func (c *client) getSession(ctx context.Context) error {
// Get session.
c.random = rand.Text()[:15]
form := url.Values{}
form.Add("aa", base64.StdEncoding.EncodeToString([]byte(flagUsername)))
form.Add("ab", base64.StdEncoding.EncodeToString([]byte(flagPassword)))
form.Add("sFormAuthStr", c.random)
res, err := c.doRequest(ctx, strings.NewReader(form.Encode()), "POST", makeAddress("cgi-bin/wlogin.cgi"), makeAddress("weblogin.htm"))
if err != nil {
return err
}
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
if strings.Contains(string(body), "Authorization Error") {
return fmt.Errorf("authorization error on wlogin.cgi")
}
// Check that auth works.
res, err = c.doRequest(ctx, nil, "GET", makeAddress("cgi-bin/cgidashboard.cgi")+fmt.Sprintf("?sFormAuthStr=%s&fid=1", c.random), makeAddress(""))
if err != nil {
return err
}
defer res.Body.Close()
body, _ = io.ReadAll(res.Body)
if strings.Contains(string(body), "Authorization Error") {
return fmt.Errorf("authorization error on cgidashboard.cgi")
}
return nil
}
func (c *client) reboot(ctx context.Context) error {
form := url.Values{}
form.Add("sReboot", "Current")
form.Add("submitbnt", "Reboot Now")
form.Add("nSch1", "0")
form.Add("nSch2", "0")
form.Add("nSch3", "0")
form.Add("nSch4", "0")
form.Add("fid", "0")
form.Add("webchange", "0")
form.Add("sFormAuthStr", c.random)
res, err := c.doRequest(ctx, strings.NewReader(form.Encode()), "POST", makeAddress("cgi-bin/reboot.cgi"), makeAddress("doc/rebootsys.sht"))
if err != nil {
return err
}
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
if strings.Contains(string(body), "Authorization Error") {
return fmt.Errorf("authorization error on reboot.cgi")
}
return nil
}
func main() {
flag.StringVar(&flagAddress, "address", "http://192.168.1.1/", "Address of Draytek admin interface")
flag.StringVar(&flagUsername, "username", "admin", "Username for authenticating to the Draytek admin interface")
flag.StringVar(&flagPassword, "password", "", "Password for authenticating to the Draytek admin interface")
flag.Parse()
if flagPassword == "" {
log.Fatalf("-password must be specified")
}
ctx := context.Background()
jar, _ := cookiejar.New(nil)
c := client{
jar: jar,
}
err := c.getSession(ctx)
if err != nil {
log.Fatalf("Could not get session: %v", err)
}
if err := c.reboot(ctx); err != nil {
log.Fatalf("Reboot failed: %v", err)
}
log.Printf("Rebooted!")
}