package onvif import ( "context" "errors" "net" "net/url" "strings" ) var ( ErrTargetNotAllowed = errors.New("目标地址不在获准网段内") ErrAddressInvalid = errors.New("设备地址格式不正确") ) type Policy struct{ Networks []*net.IPNet } func ParsePolicy(value string) (Policy, error) { var policy Policy for _, item := range strings.Split(value, ",") { item = strings.TrimSpace(item) if item == "" { continue } _, network, err := net.ParseCIDR(item) if err != nil { return Policy{}, ErrTargetNotAllowed } policy.Networks = append(policy.Networks, network) } if len(policy.Networks) == 0 { return Policy{}, ErrTargetNotAllowed } return policy, nil } func (p Policy) ValidateURL(ctx context.Context, raw string, schemes ...string) (*url.URL, net.IP, error) { u, err := url.Parse(strings.TrimSpace(raw)) if err != nil || u.Hostname() == "" || u.User != nil || u.Fragment != "" { return nil, nil, ErrAddressInvalid } for key := range u.Query() { lower := strings.ToLower(key) for _, sensitive := range []string{"user", "password", "passwd", "token", "auth", "credential", "secret", "key"} { if strings.Contains(lower, sensitive) { return nil, nil, ErrAddressInvalid } } } allowedScheme := false for _, scheme := range schemes { if strings.EqualFold(u.Scheme, scheme) { allowedScheme = true } } if !allowedScheme { return nil, nil, ErrAddressInvalid } addresses, err := net.DefaultResolver.LookupIP(ctx, "ip", u.Hostname()) if err != nil || len(addresses) == 0 { return nil, nil, ErrTargetNotAllowed } for _, address := range addresses { ok := false for _, network := range p.Networks { if network.Contains(address) { ok = true break } } if !ok { return nil, nil, ErrTargetNotAllowed } } return u, addresses[0], nil }