From 9915e0e2b18308cfb87c59449b2ed3c7697f259a Mon Sep 17 00:00:00 2001 From: Fabian Wiesel Date: Fri, 11 Mar 2022 11:26:51 +0100 Subject: [PATCH] Parse f5vpn urls After an endpoint-inspection, the webpage forwards to an f5vpn url, which can now be passed on to gof5 to extract the session-id itself. Only missing to be a proper f5vpn handler is logging --- cmd/gof5/main.go | 6 ++++++ pkg/client/client.go | 48 +++++++++++++++++++++++++++++++++++++++++++- pkg/client/http.go | 5 ++++- 3 files changed, 57 insertions(+), 2 deletions(-) diff --git a/cmd/gof5/main.go b/cmd/gof5/main.go index 2f88f03..8ce211b 100644 --- a/cmd/gof5/main.go +++ b/cmd/gof5/main.go @@ -61,6 +61,12 @@ func main() { fatal(err) } + if flag.NArg() > 0 { + if err := client.UrlHandlerF5Vpn(&opts, flag.Arg(0)); err != nil { + fatal(err) + } + } + if err := client.Connect(&opts); err != nil { fatal(err) } diff --git a/pkg/client/client.go b/pkg/client/client.go index 716a012..b3ebe48 100644 --- a/pkg/client/client.go +++ b/pkg/client/client.go @@ -32,9 +32,55 @@ type Options struct { Sel bool Version bool ProfileIndex int + ProfileName string Renegotiation tls.RenegotiationSupport } +func UrlHandlerF5Vpn(opts *Options, s string) error { + u, err := url.Parse(s) + if err != nil { + return err + } + + if u.Scheme != "f5-vpn" { + return fmt.Errorf("invalid scheme %v expected f5-vpn", u.Scheme) + } + + m, err := url.ParseQuery(u.RawQuery) + if err != nil { + return err + } + + resourceTypes := m["resourcetype"] + resourceNames := m["resourcename"] + if len(resourceTypes) == len(resourceNames) { + for i := range resourceTypes { + if resourceTypes[i] == "network_access" { + opts.ProfileName = resourceNames[i] + break + } + } + } + + opts.Server = m["server"][0] + tokenUrl := fmt.Sprintf("%s://%s:%s/vdesk/get_sessid_for_token.php3", m["protocol"][0], opts.Server, m["port"][0]) + request, err := http.NewRequest(http.MethodGet, tokenUrl, nil) + if err != nil { + return err + } + otc := m["otc"] + request.Header.Add("Content-Type", "application/x-www-form-urlencoded") + request.Header.Add("X-Access-Session-Token", otc[len(otc)-1]) + + response, err := http.DefaultClient.Do(request) + if err != nil { + return err + } + + opts.SessionID = response.Header.Get("X-Access-Session-ID") + return nil +} + func Connect(opts *Options) error { if opts.Server == "" { fmt.Print("Enter server address: ") @@ -152,7 +198,7 @@ func Connect(opts *Options) error { return fmt.Errorf("wrong response code on profiles get: %d", resp.StatusCode) } - profile, err := parseProfile(resp.Body, opts.ProfileIndex) + profile, err := parseProfile(resp.Body, opts.ProfileIndex, opts.ProfileName) if err != nil { return fmt.Errorf("failed to parse VPN profiles: %s", err) } diff --git a/pkg/client/http.go b/pkg/client/http.go index 4df8ffe..331b207 100644 --- a/pkg/client/http.go +++ b/pkg/client/http.go @@ -307,7 +307,7 @@ func login(c *http.Client, server string, username, password *string) error { return nil } -func parseProfile(reader io.ReadCloser, profileIndex int) (string, error) { +func parseProfile(reader io.ReadCloser, profileIndex int, profileName string) (string, error) { var profiles config.Profiles dec := xml.NewDecoder(reader) err := dec.Decode(&profiles) @@ -319,6 +319,9 @@ func parseProfile(reader io.ReadCloser, profileIndex int) (string, error) { if profiles.Type == "VPN" { prfls := make([]string, len(profiles.Favorites)) for i, p := range profiles.Favorites { + if profileName != "" && profileName == p.Name { + profileIndex = i + } prfls[i] = fmt.Sprintf("%d:%s", i, p.Name) } log.Printf("Found F5 VPN profiles: %q", prfls)