package ice
import (
"net"
"strings"
)
func validateIPString(ipStr string ) (net .IP , bool , error ) {
ip := net .ParseIP (ipStr )
if ip == nil {
return nil , false , ErrInvalidNAT1To1IPMapping
}
return ip , (ip .To4 () != nil ), nil
}
type ipMapping struct {
ipSole net .IP
ipMap map [string ]net .IP
valid bool
}
func (m *ipMapping ) setSoleIP (ip net .IP ) error {
if m .ipSole != nil || len (m .ipMap ) > 0 {
return ErrInvalidNAT1To1IPMapping
}
m .ipSole = ip
m .valid = true
return nil
}
func (m *ipMapping ) addIPMapping (locIP , extIP net .IP ) error {
if m .ipSole != nil {
return ErrInvalidNAT1To1IPMapping
}
locIPStr := locIP .String ()
if _ , ok := m .ipMap [locIPStr ]; ok {
return ErrInvalidNAT1To1IPMapping
}
m .ipMap [locIPStr ] = extIP
m .valid = true
return nil
}
func (m *ipMapping ) findExternalIP (locIP net .IP ) (net .IP , error ) {
if !m .valid {
return locIP , nil
}
if m .ipSole != nil {
return m .ipSole , nil
}
extIP , ok := m .ipMap [locIP .String ()]
if !ok {
return nil , ErrExternalMappedIPNotFound
}
return extIP , nil
}
type externalIPMapper struct {
ipv4Mapping ipMapping
ipv6Mapping ipMapping
candidateType CandidateType
}
func newExternalIPMapper(
candidateType CandidateType ,
ips []string ,
) (*externalIPMapper , error ) {
if len (ips ) == 0 {
return nil , nil
}
if candidateType == CandidateTypeUnspecified {
candidateType = CandidateTypeHost
} else if candidateType != CandidateTypeHost && candidateType != CandidateTypeServerReflexive {
return nil , ErrUnsupportedNAT1To1IPCandidateType
}
mapper := &externalIPMapper {
ipv4Mapping : ipMapping {ipMap : map [string ]net .IP {}},
ipv6Mapping : ipMapping {ipMap : map [string ]net .IP {}},
candidateType : candidateType ,
}
for _ , extIPStr := range ips {
ipPair := strings .Split (extIPStr , "/" )
if len (ipPair ) == 0 || len (ipPair ) > 2 {
return nil , ErrInvalidNAT1To1IPMapping
}
extIP , isExtIPv4 , err := validateIPString (ipPair [0 ])
if err != nil {
return nil , err
}
if len (ipPair ) == 1 {
if isExtIPv4 {
if err := mapper .ipv4Mapping .setSoleIP (extIP ); err != nil {
return nil , err
}
} else {
if err := mapper .ipv6Mapping .setSoleIP (extIP ); err != nil {
return nil , err
}
}
} else {
locIP , isLocIPv4 , err := validateIPString (ipPair [1 ])
if err != nil {
return nil , err
}
if isExtIPv4 {
if !isLocIPv4 {
return nil , ErrInvalidNAT1To1IPMapping
}
if err := mapper .ipv4Mapping .addIPMapping (locIP , extIP ); err != nil {
return nil , err
}
} else {
if isLocIPv4 {
return nil , ErrInvalidNAT1To1IPMapping
}
if err := mapper .ipv6Mapping .addIPMapping (locIP , extIP ); err != nil {
return nil , err
}
}
}
}
return mapper , nil
}
func (m *externalIPMapper ) findExternalIP (localIPStr string ) (net .IP , error ) {
locIP , isLocIPv4 , err := validateIPString (localIPStr )
if err != nil {
return nil , err
}
if isLocIPv4 {
return m .ipv4Mapping .findExternalIP (locIP )
}
return m .ipv6Mapping .findExternalIP (locIP )
}
The pages are generated with Golds v0.8.2 . (GOOS=linux GOARCH=amd64)
Golds is a Go 101 project developed by Tapir Liu .
PR and bug reports are welcome and can be submitted to the issue list .
Please follow @zigo_101 (reachable from the left QR code) to get the latest news of Golds .