77 lines
1.8 KiB
Go
77 lines
1.8 KiB
Go
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
|
|
}
|