| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293 |
- package cli
-
- import (
- "context"
- "io"
- "net"
- "net/http"
- "strings"
-
- "github.com/9seconds/mtg/v2/essentials"
- "github.com/9seconds/mtg/v2/internal/config"
- "github.com/9seconds/mtg/v2/mtglib"
- )
-
- // defaultPublicIPEndpoints is the fallback used when network.public-ip-endpoints
- // is not set in config. Each endpoint must return the client's public IP as a
- // single address in the plain-text response body.
- var defaultPublicIPEndpoints = []string{
- "https://ifconfig.co",
- "https://icanhazip.com",
- "https://ifconfig.me",
- }
-
- // resolvePublicIPEndpoints returns the configured endpoint list, falling back
- // to defaultPublicIPEndpoints when none are configured.
- func resolvePublicIPEndpoints(configured []config.TypeHttpsURL) []string {
- if len(configured) == 0 {
- return defaultPublicIPEndpoints
- }
-
- out := make([]string, 0, len(configured))
- for _, u := range configured {
- if v := u.Get(nil); v != nil {
- out = append(out, v.String())
- }
- }
-
- if len(out) == 0 {
- return defaultPublicIPEndpoints
- }
-
- return out
- }
-
- func getIP(ctx context.Context, ntw mtglib.Network, protocol string, endpoints []string) net.IP {
- dialer := ntw.NativeDialer()
- client := ntw.MakeHTTPClient(func(ctx context.Context, network, address string) (essentials.Conn, error) {
- conn, err := dialer.DialContext(ctx, protocol, address)
- if err != nil {
- return nil, err
- }
- return essentials.WrapNetConn(conn), err
- })
-
- for _, endpoint := range endpoints {
- if ip := fetchPublicIP(ctx, client, endpoint); ip != nil {
- return ip
- }
- }
-
- return nil
- }
-
- func fetchPublicIP(ctx context.Context, client *http.Client, endpoint string) net.IP {
- req, err := http.NewRequestWithContext(ctx, http.MethodGet, endpoint, nil)
- if err != nil {
- return nil
- }
-
- req.Header.Set("Accept", "text/plain")
- req.Header.Set("User-Agent", "curl/8")
-
- resp, err := client.Do(req)
- if err != nil {
- return nil
- }
-
- defer func() {
- io.Copy(io.Discard, resp.Body) //nolint: errcheck
- resp.Body.Close() //nolint: errcheck
- }()
-
- if resp.StatusCode != http.StatusOK {
- return nil
- }
-
- data, err := io.ReadAll(resp.Body)
- if err != nil {
- return nil
- }
-
- return net.ParseIP(strings.TrimSpace(string(data)))
- }
|