mirror of
https://github.com/luscis/openlan.git
synced 2025-09-26 20:41:29 +08:00
fea: support vxlan over ipsec.
This commit is contained in:
@@ -26,6 +26,7 @@ func (o Output) Add(c *cli.Context) error {
|
||||
Segment: c.Int("segment"),
|
||||
Protocol: c.String("protocol"),
|
||||
DstPort: c.Int("dstport"),
|
||||
Secret: c.String("secret"),
|
||||
}
|
||||
url := o.Url(c.String("url"), network)
|
||||
clt := o.NewHttp(c.String("token"))
|
||||
@@ -99,8 +100,7 @@ func (o Output) Commands(app *api.App) {
|
||||
&cli.StringFlag{Name: "protocol"},
|
||||
&cli.StringFlag{Name: "dstport"},
|
||||
//&cli.StringFlag{Name: "connection"},
|
||||
//&cli.StringFlag{Name: "secret"},
|
||||
//&cli.StringFlag{Name: "auth"},
|
||||
&cli.StringFlag{Name: "secret"},
|
||||
},
|
||||
Action: o.Add,
|
||||
},
|
||||
|
20
dist/rootfs/var/openlan/script/switch.sh
vendored
20
dist/rootfs/var/openlan/script/switch.sh
vendored
@@ -24,24 +24,4 @@ cat >> /etc/openlan/switch/switch.json << EOF
|
||||
EOF
|
||||
fi
|
||||
|
||||
if echo $ENABLED | grep -w "confd" -q; then
|
||||
# wait confd service
|
||||
while true; do
|
||||
if [ -e /var/openlan/confd/confd.sock ]; then
|
||||
break
|
||||
fi
|
||||
sleep 5
|
||||
done
|
||||
fi
|
||||
|
||||
if echo $ENABLED | grep -w "openvswitch" -q; then
|
||||
# wait openvswitch service
|
||||
while true; do
|
||||
if [ -e /var/run/openvswitch/db.sock ]; then
|
||||
break
|
||||
fi
|
||||
sleep 5
|
||||
done
|
||||
fi
|
||||
|
||||
exec /usr/bin/openlan-switch -conf:dir /etc/openlan/switch -log:level 20
|
||||
|
@@ -8,6 +8,7 @@ services:
|
||||
entrypoint: ["/var/openlan/script/ipsec.sh"]
|
||||
volumes:
|
||||
- /opt/openlan/etc/ipsecd.d:/etc/ipsec.d
|
||||
- /opt/openlan/run/pluto:/run/pluto
|
||||
switch:
|
||||
restart: always
|
||||
image: "luscis/openlan:latest.x86_64"
|
||||
@@ -17,6 +18,7 @@ services:
|
||||
volumes:
|
||||
- /opt/openlan/etc/openlan:/etc/openlan
|
||||
- /opt/openlan/etc/ipsecd.d:/etc/ipsec.d
|
||||
- /opt/openlan/run/pluto:/run/pluto
|
||||
depends_on:
|
||||
- ipsec
|
||||
proxy:
|
||||
|
@@ -2,5 +2,3 @@
|
||||
- [软件安装](install.md)
|
||||
- [分支接入](central.md)
|
||||
- [多区域互联](multiarea.md)
|
||||
- [全互连网络](fabric.md)
|
||||
- [IPSec网络](ipsec.md)
|
||||
|
@@ -6,4 +6,5 @@ type Output struct {
|
||||
Remote string `json:"remote"`
|
||||
DstPort int `json:"dstport,omitempty"`
|
||||
Link string `json:"link,omitempty"` // link name
|
||||
Secret string `json:"secret"`
|
||||
}
|
||||
|
@@ -8,6 +8,7 @@ type Output struct {
|
||||
Remote string
|
||||
Segment int
|
||||
Device string
|
||||
Secret string
|
||||
RxBytes uint64
|
||||
TxBytes uint64
|
||||
ErrPkt uint64
|
||||
|
@@ -130,6 +130,7 @@ func NewOutputSchema(o *Output) schema.Output {
|
||||
Device: o.Device,
|
||||
RxBytes: o.RxBytes,
|
||||
TxBytes: o.TxBytes,
|
||||
Secret: o.Secret,
|
||||
AliveTime: o.UpTime(),
|
||||
}
|
||||
}
|
||||
|
@@ -9,7 +9,6 @@ type Index struct {
|
||||
OnLines []OnLine `json:"online"`
|
||||
Network []Network `json:"network"`
|
||||
Clients []VPNClient `json:"clients"`
|
||||
States []EspState `json:"states"`
|
||||
Outputs []Output `json:"output"`
|
||||
}
|
||||
|
||||
|
@@ -1,45 +0,0 @@
|
||||
package schema
|
||||
|
||||
import "net"
|
||||
|
||||
type Esp struct {
|
||||
Name string `json:"name"`
|
||||
Address string `json:"address"`
|
||||
Members []EspMember `json:"members,omitempty"`
|
||||
}
|
||||
|
||||
type EspState struct {
|
||||
Name string `json:"name"`
|
||||
AliveTime int64 `json:"alive"`
|
||||
Spi int `json:"spi"`
|
||||
Local net.IP `json:"source"`
|
||||
Mode uint8 `json:"mode"`
|
||||
Proto uint8 `json:"proto"`
|
||||
Remote net.IP `json:"destination"`
|
||||
Auth string `json:"auth"`
|
||||
Crypt string `json:"crypt"`
|
||||
Encap string `json:"encap" `
|
||||
RemotePort int `json:"remotePort"`
|
||||
TxBytes uint64 `json:"txBytes"`
|
||||
TxPackages uint64 `json:"txPackages"`
|
||||
RxBytes uint64 `json:"rxBytes"`
|
||||
RxPackages uint64 `json:"rxPackages"`
|
||||
}
|
||||
|
||||
type EspPolicy struct {
|
||||
Name string `json:"name"`
|
||||
Spi int `json:"spi"`
|
||||
Local net.IP `json:"local"`
|
||||
Remote net.IP `json:"remote"`
|
||||
Source string `json:"source"`
|
||||
Dest string `json:"destination"`
|
||||
Priority int `json:"priority"`
|
||||
}
|
||||
|
||||
type EspMember struct {
|
||||
Name string `json:"name"`
|
||||
Spi uint32 `json:"spi"`
|
||||
Peer string `json:"peer"`
|
||||
State EspState `json:"state"`
|
||||
Policy []EspPolicy `json:"policy"`
|
||||
}
|
@@ -6,6 +6,7 @@ type Output struct {
|
||||
Remote string `json:"remote"`
|
||||
DstPort int `json:"dstPort"`
|
||||
Segment int `json:"segment"`
|
||||
Secret string `json:"secret"`
|
||||
Device string `json:"device"`
|
||||
RxBytes uint64 `json:"rxBytes"`
|
||||
TxBytes uint64 `json:"txBytes"`
|
||||
|
@@ -4,6 +4,7 @@ import (
|
||||
"fmt"
|
||||
"net"
|
||||
"strings"
|
||||
"text/template"
|
||||
"time"
|
||||
|
||||
"github.com/luscis/openlan/pkg/api"
|
||||
@@ -30,30 +31,34 @@ func NewNetworker(c *co.Network) api.Networker {
|
||||
return obj
|
||||
}
|
||||
|
||||
func toLinkName(protocol, remote string, segment int) string {
|
||||
if protocol == "gre" {
|
||||
return fmt.Sprintf("%s%d", "gre", segment)
|
||||
}
|
||||
if protocol == "vxlan" {
|
||||
return fmt.Sprintf("%s%d", "vxlan", segment)
|
||||
}
|
||||
if segment > 0 {
|
||||
return fmt.Sprintf("%s.%d", remote, segment)
|
||||
}
|
||||
return remote
|
||||
}
|
||||
|
||||
type LinuxPort struct {
|
||||
cfg co.Output
|
||||
link string
|
||||
output co.Output
|
||||
link string
|
||||
}
|
||||
|
||||
func (l *LinuxPort) String() string {
|
||||
return fmt.Sprintf("%s:%s:%d", l.cfg.Protocol, l.cfg.Remote, l.cfg.Segment)
|
||||
return fmt.Sprintf("%s:%s:%d", l.output.Protocol, l.output.Remote, l.output.Segment)
|
||||
}
|
||||
|
||||
func (l *LinuxPort) GenName() {
|
||||
if l.link != "" {
|
||||
return
|
||||
}
|
||||
|
||||
cfg := l.cfg
|
||||
if cfg.Protocol == "gre" {
|
||||
l.link = fmt.Sprintf("%s%d", "gre", cfg.Segment)
|
||||
} else if cfg.Protocol == "vxlan" {
|
||||
l.link = fmt.Sprintf("%s%d", "vxlan", cfg.Segment)
|
||||
} else if cfg.Segment > 0 {
|
||||
l.link = fmt.Sprintf("%s.%d", cfg.Remote, cfg.Segment)
|
||||
} else {
|
||||
l.link = cfg.Remote
|
||||
}
|
||||
out := l.output
|
||||
l.link = toLinkName(out.Protocol, out.Remote, out.Segment)
|
||||
}
|
||||
|
||||
type WorkerImpl struct {
|
||||
@@ -179,7 +184,13 @@ func (w *WorkerImpl) AddPhysical(bridge string, output string) {
|
||||
}
|
||||
|
||||
func (w *WorkerImpl) addOutput(bridge string, port *LinuxPort) {
|
||||
cfg := port.cfg
|
||||
if port.output.Secret != "" {
|
||||
if err := w.addSecConn(port); err != nil {
|
||||
w.out.Error("WorkerImpl.addOutput %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
cfg := port.output
|
||||
out := &models.Output{
|
||||
Network: w.cfg.Name,
|
||||
NewTime: time.Now().Unix(),
|
||||
@@ -189,7 +200,6 @@ func (w *WorkerImpl) addOutput(bridge string, port *LinuxPort) {
|
||||
}
|
||||
|
||||
mtu := 0
|
||||
port.GenName()
|
||||
if cfg.Protocol == "gre" {
|
||||
mtu = 1450
|
||||
link := &nl.Gretap{
|
||||
@@ -379,8 +389,9 @@ func (w *WorkerImpl) Start(v api.Switcher) {
|
||||
|
||||
for _, output := range cfg.Outputs {
|
||||
port := &LinuxPort{
|
||||
cfg: output,
|
||||
output: output,
|
||||
}
|
||||
port.GenName()
|
||||
w.addOutput(cfg.Bridge.Name, port)
|
||||
w.outputs = append(w.outputs, port)
|
||||
}
|
||||
@@ -458,7 +469,13 @@ func (w *WorkerImpl) DelPhysical(bridge string, output string) {
|
||||
}
|
||||
|
||||
func (w *WorkerImpl) delOutput(bridge string, port *LinuxPort) {
|
||||
cfg := port.cfg
|
||||
if port.output.Secret != "" {
|
||||
if err := w.delSecConn(port); err != nil {
|
||||
w.out.Error("WorkerImpl.AddOutput %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
cfg := port.output
|
||||
w.out.Info("WorkerImpl.delOutput %s %s", port.link, port.String())
|
||||
|
||||
cache.Output.Del(port.link)
|
||||
@@ -484,7 +501,7 @@ func (w *WorkerImpl) delOutput(bridge string, port *LinuxPort) {
|
||||
w.out.Error("WorkerImpl.LinkDel %s %s", link.Name, err)
|
||||
return
|
||||
}
|
||||
} else if port.cfg.Segment > 0 {
|
||||
} else if port.output.Segment > 0 {
|
||||
link := &nl.Vlan{
|
||||
LinkAttrs: nl.LinkAttrs{
|
||||
Name: port.link,
|
||||
@@ -1069,43 +1086,161 @@ func (w *WorkerImpl) ACLer() api.ACLer {
|
||||
return w.acl
|
||||
}
|
||||
|
||||
const (
|
||||
vxlanConn = `
|
||||
conn vxlan{{ .Segment }}-in
|
||||
keyingtries=%forever
|
||||
auto=route
|
||||
ike=aes_gcm256-sha2_256
|
||||
esp=aes_gcm256
|
||||
ikev2=insist
|
||||
type=transport
|
||||
left=%defaultroute
|
||||
right={{ .Remote }}
|
||||
authby=secret
|
||||
leftprotoport=udp/8472
|
||||
rightprotoport=udp
|
||||
|
||||
conn vxlan{{ .Segment }}-out
|
||||
keyingtries=%forever
|
||||
auto=route
|
||||
ike=aes_gcm256-sha2_256
|
||||
esp=aes_gcm256
|
||||
ikev2=insist
|
||||
type=transport
|
||||
left=%defaultroute
|
||||
right={{ .Remote }}
|
||||
authby=secret
|
||||
leftprotoport=udp
|
||||
rightprotoport=udp/8472
|
||||
`
|
||||
greConn = `
|
||||
conn gre{{ .Segment }}
|
||||
keyingtries=%forever
|
||||
auto=route
|
||||
ike=aes_gcm256-sha2_256
|
||||
esp=aes_gcm256
|
||||
ikev2=insist
|
||||
type=transport
|
||||
left=%defaultroute
|
||||
right={{ .Remote }}
|
||||
authby=secret
|
||||
leftprotoport=gre
|
||||
rightprotoport=gre
|
||||
`
|
||||
secretConn = `
|
||||
%any {{ .Remote }} : PSK "{{ .Secret }}"
|
||||
`
|
||||
)
|
||||
|
||||
func (w *WorkerImpl) addSecConn(port *LinuxPort) error {
|
||||
connTmpl := ""
|
||||
secTmpl := ""
|
||||
|
||||
name := port.link
|
||||
data := port.output
|
||||
if data.Protocol == "vxlan" {
|
||||
connTmpl = vxlanConn
|
||||
secTmpl = secretConn
|
||||
} else if data.Protocol == "gre" {
|
||||
connTmpl = vxlanConn
|
||||
secTmpl = secretConn
|
||||
}
|
||||
|
||||
if secTmpl != "" {
|
||||
file := fmt.Sprintf("/etc/ipsec.d/%s.secrets", name)
|
||||
out, err := libol.CreateFile(file)
|
||||
if err != nil || out == nil {
|
||||
return err
|
||||
}
|
||||
defer out.Close()
|
||||
if tmpl, err := template.New("main").Parse(secTmpl); err != nil {
|
||||
return err
|
||||
} else {
|
||||
if err := tmpl.Execute(out, data); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
libol.Exec("ipsec", "auto", "--rereadsecrets")
|
||||
}
|
||||
if connTmpl != "" {
|
||||
file := fmt.Sprintf("/etc/ipsec.d/%s.conf", name)
|
||||
out, err := libol.CreateFile(file)
|
||||
if err != nil || out == nil {
|
||||
return err
|
||||
}
|
||||
defer out.Close()
|
||||
if tmpl, err := template.New("main").Parse(connTmpl); err != nil {
|
||||
return err
|
||||
} else {
|
||||
if err := tmpl.Execute(out, data); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if data.Protocol == "vxlan" {
|
||||
libol.Exec("ipsec", "auto", "--start", "--asynchronous", name+"-in")
|
||||
libol.Exec("ipsec", "auto", "--start", "--asynchronous", name+"-out")
|
||||
} else if data.Protocol == "gre" {
|
||||
libol.Exec("ipsec", "auto", "--start", "--asynchronous", name)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (w *WorkerImpl) AddOutput(data schema.Output) {
|
||||
output := co.Output{
|
||||
Segment: data.Segment,
|
||||
Protocol: data.Protocol,
|
||||
Remote: data.Remote,
|
||||
DstPort: data.DstPort,
|
||||
Secret: data.Secret,
|
||||
}
|
||||
w.cfg.Outputs = append(w.cfg.Outputs, output)
|
||||
port := &LinuxPort{
|
||||
cfg: output,
|
||||
output: output,
|
||||
}
|
||||
port.GenName()
|
||||
w.addOutput(w.cfg.Bridge.Name, port)
|
||||
w.outputs = append(w.outputs, port)
|
||||
}
|
||||
|
||||
// ipsec auto --delete --asynchronous tunx-in-1
|
||||
func (w *WorkerImpl) delSecConn(port *LinuxPort) error {
|
||||
data := port.output
|
||||
name := port.link
|
||||
|
||||
if data.Protocol == "vxlan" {
|
||||
libol.Exec("ipsec", "auto", "--delete", "--asynchronous", name+"-in")
|
||||
libol.Exec("ipsec", "auto", "--delete", "--asynchronous", name+"-out")
|
||||
} else if data.Protocol == "gre" {
|
||||
libol.Exec("ipsec", "auto", "--delete", "--asynchronous", name)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (w *WorkerImpl) DelOutput(device string) {
|
||||
var linuxport *LinuxPort
|
||||
var port *LinuxPort
|
||||
for _, v := range w.outputs {
|
||||
if v.link == device {
|
||||
linuxport = v
|
||||
port = v
|
||||
break
|
||||
}
|
||||
}
|
||||
if linuxport == nil {
|
||||
if port == nil {
|
||||
return
|
||||
}
|
||||
Outputs := make([]co.Output, 0, len(w.cfg.Outputs))
|
||||
for _, v := range w.cfg.Outputs {
|
||||
if v != linuxport.cfg {
|
||||
if v != port.output {
|
||||
Outputs = append(Outputs, v)
|
||||
}
|
||||
}
|
||||
w.cfg.Outputs = Outputs
|
||||
w.delOutput(w.cfg.Bridge.Name, linuxport)
|
||||
w.delOutput(w.cfg.Bridge.Name, port)
|
||||
outputs := make([]*LinuxPort, 0, len(w.outputs))
|
||||
for _, v := range w.outputs {
|
||||
if v != linuxport {
|
||||
if v != port {
|
||||
outputs = append(outputs, v)
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user