Files
openlan/pkg/config/ipsec.go
2023-11-13 17:47:17 +08:00

267 lines
5.2 KiB
Go
Executable File

package config
import (
"fmt"
"net"
"strconv"
"strings"
"github.com/luscis/openlan/pkg/libol"
)
var (
EspAuth = "8bc736635c0642aebc20ba5420c3e93a"
EspCrypt = "4ac161f6635843b8b02c60cc36822515"
EspLocalUdp = 4500
EspRemoteUdp = 4500
)
func Addr2Cidr(addr string) string {
if !strings.Contains(addr, "/") {
return addr + "/32"
}
return addr
}
func SetLocalUdp(port string) {
if udp, err := strconv.Atoi(port); err == nil {
EspLocalUdp = udp
}
}
type EspState struct {
Local string `json:"local,omitempty"`
LocalIp net.IP `json:"localAddr,omitempty"`
Remote string `json:"remote,omitempty"`
RemotePort int `json:"remotePort,omitempty"`
RemoteIp net.IP `json:"remoteAddr,omitempty"`
Encap string `json:"encapsulation,omitempty"`
Auth string `json:"auth,omitempty"`
Crypt string `json:"crypt,omitempty"`
}
func (s *EspState) Padding(value string, size int) string {
return strings.Repeat(value, 64/len(value))[:size]
}
func (s *EspState) Merge(obj *EspState) {
if obj == nil {
return
}
if s.Local == "" {
s.Local = obj.Local
}
if s.Auth == "" {
s.Auth = obj.Auth
}
if s.Crypt == "" {
s.Crypt = obj.Crypt
}
if s.RemotePort == 0 {
s.RemotePort = obj.RemotePort
}
}
func (s *EspState) Correct() {
if addr, _ := net.LookupIP(s.Local); len(addr) > 0 {
s.LocalIp = addr[0]
}
if addr, _ := net.LookupIP(s.Remote); len(addr) > 0 {
s.RemoteIp = addr[0]
}
if s.LocalIp == nil && s.RemoteIp != nil {
addr, _ := libol.GetLocalByGw(s.RemoteIp.String())
s.Local = addr.String()
s.LocalIp = addr
}
if s.Crypt == "" {
s.Crypt = s.Auth
}
if s.Auth == "" {
s.Auth = EspAuth
}
if s.Crypt == "" {
s.Crypt = EspCrypt
}
if s.Encap == "" {
s.Encap = "udp"
}
if s.RemotePort == 0 {
s.RemotePort = EspRemoteUdp
}
s.Auth = s.Padding(s.Auth, 32)
s.Crypt = s.Padding(s.Crypt, 32)
}
type EspPolicy struct {
Source string `json:"source,omitempty"`
Dest string `json:"destination,omitempty"`
Priority int `json:"priority,omitempty"`
}
func (p *EspPolicy) Correct() {
if p.Source == "" {
p.Source = "0.0.0.0/0"
}
p.Priority = 128 - libol.GetPrefixLen(p.Dest)
}
type EspMember struct {
Name string `json:"name,omitempty"`
Address string `json:"address,omitempty"`
Peer string `json:"peer"`
Spi int `json:"spi"`
State EspState `json:"state"`
Policies []*EspPolicy `json:"policies"`
}
func (m *EspMember) Correct() {
if m.Name == "" {
m.Name = fmt.Sprintf("spi:%d", m.Spi)
} else if m.Spi == 0 {
_, _ = fmt.Sscanf(m.Name, "spi:%d", &m.Spi)
}
if m.Address == "" || m.Peer == "" {
return
}
m.Peer = Addr2Cidr(m.Peer)
m.Address = Addr2Cidr(m.Address)
m.State.Correct()
if m.Policies == nil {
m.Policies = make([]*EspPolicy, 0, 2)
}
found := -1
for index, pol := range m.Policies {
pol.Correct()
if pol.Dest != m.Peer {
continue
}
found = index
}
if found < 0 {
pol := &EspPolicy{
Dest: m.Peer,
}
pol.Correct()
m.Policies = append(m.Policies, pol)
}
}
func (m *EspMember) AddPolicy(obj *EspPolicy) {
found := -1
for index, po := range m.Policies {
if po.Dest != obj.Dest {
continue
}
found = index
po.Source = obj.Source
break
}
if found < 0 {
obj.Correct()
m.Policies = append(m.Policies, obj)
}
}
func (m *EspMember) RemovePolicy(dest string) bool {
found := -1
for index, po := range m.Policies {
if po.Dest != dest {
continue
}
found = index
break
}
if found >= 0 {
copy(m.Policies[found:], m.Policies[found+1:])
m.Policies = m.Policies[:len(m.Policies)-1]
}
return found >= 0
}
type EspSpecifies struct {
Name string `json:"name"`
Address string `json:"address,omitempty"`
State EspState `json:"state,omitempty"`
Members []*EspMember `json:"members"`
Listen string `json:"listen,omitempty"`
TcpMss int `json:"tcpMss"`
}
func (n *EspSpecifies) Correct() {
if n.Listen != "" {
addr, port := libol.GetHostPort(n.Listen)
if addr != "" {
n.State.Local = addr
}
if port != "" {
SetLocalUdp(port)
}
}
n.State.Correct()
for _, m := range n.Members {
if m.Address == "" {
m.Address = n.Address
}
m.State.Merge(&n.State)
m.Correct()
}
if n.TcpMss == 0 {
n.TcpMss = 1430 // 1460 - 20 - 8
}
}
func (n *EspSpecifies) GetMember(name string) *EspMember {
for _, mem := range n.Members {
if mem.Name == name {
return mem
}
}
return nil
}
func (n *EspSpecifies) HasRemote(name, addr string) bool {
for _, mem := range n.Members {
state := mem.State
if state.Remote != name || state.RemoteIp.String() == addr {
continue
}
return true
}
return false
}
func (n *EspSpecifies) AddMember(obj *EspMember) {
found := -1
for index, mem := range n.Members {
if mem.Spi != obj.Spi && mem.Name != obj.Name {
continue
}
found = index
if len(obj.Policies) == 0 {
obj.Policies = mem.Policies
}
n.Members[index] = obj
break
}
if found < 0 {
n.Members = append(n.Members, obj)
}
}
func (n *EspSpecifies) DelMember(name string) bool {
found := -1
for index, mem := range n.Members {
if mem.Name != name {
continue
}
found = index
break
}
if found >= 0 {
copy(n.Members[found:], n.Members[found+1:])
n.Members = n.Members[:len(n.Members)-1]
}
return found >= 0
}