Files
openlan/pkg/switch/l2tp.go
2023-12-31 20:48:16 +08:00

210 lines
3.6 KiB
Go
Executable File

package cswitch
import (
"io/ioutil"
"os"
"os/exec"
"path/filepath"
"strings"
"text/template"
co "github.com/luscis/openlan/pkg/config"
"github.com/luscis/openlan/pkg/libol"
)
const (
L2TPBin = "xl2tpd"
L2TPDir = "/var/openlan/l2tp"
)
type L2TP struct {
cfg *co.L2TP
out *libol.SubLogger
uuid string
}
func NewL2TP(cfg *co.L2TP) *L2TP {
return &L2TP{
cfg: cfg,
out: libol.NewSubLogger("l2tp"),
uuid: "l2tp",
}
}
func (d *L2TP) Initialize() {
if err := os.Mkdir(L2TPDir, 0600); err != nil {
d.out.Error("OpenVPN.Initialize %s", err)
}
}
func (d *L2TP) Conf() *co.L2TP {
return d.cfg
}
func (d *L2TP) UUID() string {
return d.uuid
}
func (d *L2TP) Path() string {
return L2TPBin
}
func (d *L2TP) PidFile() string {
return filepath.Join(L2TPDir, d.uuid+".pid")
}
func (d *L2TP) ConfFile() string {
return filepath.Join(L2TPDir, d.uuid+".conf")
}
func (d *L2TP) OptionsFile() string {
return filepath.Join(L2TPDir, d.uuid+".options")
}
func (d *L2TP) Tmpl() string {
return `
[global]
listen-addr = {{ .Listen }}
{{- if .Ipsec }}
ipsec saref = yes
{{- end }}
[lns default]
ip range = {{ .StartAt }}-{{ .EndAt }}
local ip = {{ .Local }}
require chap = yes
refuse pap = yes
require authentication = yes
name = LinuxL2TP
ppp debug = yes
pppoptfile = {{ .Option }}
length bit = yes
`
}
func (d *L2TP) OptionsTmpl() string {
return `
ipcp-accept-local
ipcp-accept-remote
noccp
# noauth
crtscts
mtu 1410
mru 1410
nodefaultroute
debug
lock
{{- range .Options }}
{{ . }}
{{- end }}
`
}
func (d *L2TP) SaveConf() {
fp, err := libol.CreateFile(d.ConfFile())
if err != nil || fp == nil {
libol.Error("L2TP.SaveConf: %s", err)
return
}
defer fp.Close()
cfg := d.cfg
tmpl := d.Tmpl()
data := struct {
Listen string
Local string
StartAt string
EndAt string
Option string
Ipsec bool
}{
Listen: "0.0.0.0",
Local: cfg.Address,
StartAt: cfg.Subnet.Start,
EndAt: cfg.Subnet.End,
Option: d.OptionsFile(),
}
if cfg.IpSec == "enable" {
data.Ipsec = true
}
d.Render(fp, tmpl, data)
}
func (d *L2TP) Render(fp *os.File, tmpl string, data interface{}) {
if tmpl, err := template.New("main").Parse(tmpl); err == nil {
if err := tmpl.Execute(fp, data); err != nil {
d.out.Warn("L2TP.Render: %s", err)
return
}
} else {
d.out.Warn("L2TP.Render: %s", err)
}
}
func (d *L2TP) SaveOptions() {
fp, err := libol.CreateFile(d.OptionsFile())
if err != nil || fp == nil {
libol.Error("L2TP.SaveOptions: %s", err)
return
}
defer fp.Close()
cfg := d.cfg
tmpl := d.OptionsTmpl()
data := struct {
Options []string
}{
Options: cfg.Options,
}
d.Render(fp, tmpl, data)
}
func (d *L2TP) Start() {
if d.cfg.Subnet == nil {
return
}
d.SaveConf()
d.SaveOptions()
libol.Go(func() {
args := []string{
"-c", d.ConfFile(),
"-p", d.PidFile(),
"-D",
}
d.out.Info("L2TP.Start %s %v", d.Path(), args)
cmd := exec.Command(d.Path(), args...)
if err := cmd.Run(); err != nil {
d.out.Error("L2TP.Start %s: %s", d.uuid, err)
}
})
}
func (d *L2TP) Clean() {
files := []string{
d.PidFile(), d.ConfFile(),
}
for _, file := range files {
if err := libol.FileExist(file); err == nil {
if err := os.Remove(file); err != nil {
d.out.Warn("L2TP.Clean %s", err)
}
}
}
}
func (d *L2TP) Stop() {
if d.cfg.Subnet == nil {
return
}
if data, err := ioutil.ReadFile(d.PidFile()); err != nil {
d.out.Info("L2TP.Stop %s", err)
} else {
pid := strings.TrimSpace(string(data))
cmd := exec.Command("/usr/bin/kill", pid)
if err := cmd.Run(); err != nil {
d.out.Warn("L2TP.Stop %s: %s", pid, err)
}
}
d.Clean()
}