mirror of
https://github.com/coder/coder.git
synced 2025-07-13 21:36:50 +00:00
feat(cli): add aws check to ping p2p diagnostics (#14450)
This commit is contained in:
114
cli/cliutil/awscheck.go
Normal file
114
cli/cliutil/awscheck.go
Normal file
@ -0,0 +1,114 @@
|
||||
package cliutil
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"io"
|
||||
"net/http"
|
||||
"net/netip"
|
||||
"time"
|
||||
|
||||
"golang.org/x/xerrors"
|
||||
)
|
||||
|
||||
const AWSIPRangesURL = "https://ip-ranges.amazonaws.com/ip-ranges.json"
|
||||
|
||||
type awsIPv4Prefix struct {
|
||||
Prefix string `json:"ip_prefix"`
|
||||
Region string `json:"region"`
|
||||
Service string `json:"service"`
|
||||
NetworkBorderGroup string `json:"network_border_group"`
|
||||
}
|
||||
|
||||
type awsIPv6Prefix struct {
|
||||
Prefix string `json:"ipv6_prefix"`
|
||||
Region string `json:"region"`
|
||||
Service string `json:"service"`
|
||||
NetworkBorderGroup string `json:"network_border_group"`
|
||||
}
|
||||
|
||||
type AWSIPRanges struct {
|
||||
V4 []netip.Prefix
|
||||
V6 []netip.Prefix
|
||||
}
|
||||
|
||||
type awsIPRangesResponse struct {
|
||||
SyncToken string `json:"syncToken"`
|
||||
CreateDate string `json:"createDate"`
|
||||
IPV4Prefixes []awsIPv4Prefix `json:"prefixes"`
|
||||
IPV6Prefixes []awsIPv6Prefix `json:"ipv6_prefixes"`
|
||||
}
|
||||
|
||||
func FetchAWSIPRanges(ctx context.Context, url string) (*AWSIPRanges, error) {
|
||||
client := &http.Client{}
|
||||
reqCtx, reqCancel := context.WithTimeout(ctx, 5*time.Second)
|
||||
defer reqCancel()
|
||||
req, _ := http.NewRequestWithContext(reqCtx, http.MethodGet, url, nil)
|
||||
resp, err := client.Do(req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
b, _ := io.ReadAll(resp.Body)
|
||||
return nil, xerrors.Errorf("unexpected status code %d: %s", resp.StatusCode, b)
|
||||
}
|
||||
|
||||
var body awsIPRangesResponse
|
||||
err = json.NewDecoder(resp.Body).Decode(&body)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("json decode: %w", err)
|
||||
}
|
||||
|
||||
out := &AWSIPRanges{
|
||||
V4: make([]netip.Prefix, 0, len(body.IPV4Prefixes)),
|
||||
V6: make([]netip.Prefix, 0, len(body.IPV6Prefixes)),
|
||||
}
|
||||
|
||||
for _, p := range body.IPV4Prefixes {
|
||||
prefix, err := netip.ParsePrefix(p.Prefix)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("parse ip prefix: %w", err)
|
||||
}
|
||||
if prefix.Addr().Is6() {
|
||||
return nil, xerrors.Errorf("ipv4 prefix contains ipv6 address: %s", p.Prefix)
|
||||
}
|
||||
out.V4 = append(out.V4, prefix)
|
||||
}
|
||||
|
||||
for _, p := range body.IPV6Prefixes {
|
||||
prefix, err := netip.ParsePrefix(p.Prefix)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("parse ip prefix: %w", err)
|
||||
}
|
||||
if prefix.Addr().Is4() {
|
||||
return nil, xerrors.Errorf("ipv6 prefix contains ipv4 address: %s", p.Prefix)
|
||||
}
|
||||
out.V6 = append(out.V6, prefix)
|
||||
}
|
||||
|
||||
return out, nil
|
||||
}
|
||||
|
||||
// CheckIP checks if the given IP address is an AWS IP.
|
||||
func (r *AWSIPRanges) CheckIP(ip netip.Addr) bool {
|
||||
if ip.IsLoopback() || ip.IsLinkLocalMulticast() || ip.IsLinkLocalUnicast() || ip.IsPrivate() {
|
||||
return false
|
||||
}
|
||||
|
||||
if ip.Is4() {
|
||||
for _, p := range r.V4 {
|
||||
if p.Contains(ip) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for _, p := range r.V6 {
|
||||
if p.Contains(ip) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
Reference in New Issue
Block a user