143 lines
3.4 KiB
Go
143 lines
3.4 KiB
Go
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!")
|
|
}
|