- 新增日志中心功能 (api/logapi.go + Logs.vue) - 新增GRE协议服务支持 (service/gre/) - 新增流量监控组件 (TrafficChart.vue) - 新增L2TP/IPSec测试用例 - 新增日志轮转服务 (logrotate.go) - 新增部署脚本 (scripts/install.sh, uninstall.sh, service文件) - 更新i18n国际化文件 - 优化后端API和前端路由
243 lines
6.9 KiB
Go
243 lines
6.9 KiB
Go
package ipsec
|
|
|
|
import (
|
|
"strings"
|
|
"testing"
|
|
|
|
"vpn-platform/backend/internal/service"
|
|
)
|
|
|
|
func TestValidateDefaults(t *testing.T) {
|
|
cfg, err := New().Validate(map[string]interface{}{
|
|
"remote_gateway": "203.0.113.1",
|
|
"local_subnets": "192.168.1.0/24",
|
|
"remote_subnets": "192.168.2.0/24",
|
|
})
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
defaults := []struct {
|
|
key string
|
|
expected string
|
|
}{
|
|
{"ike_version", "ikev2"},
|
|
{"ike_proposal", "aes256-sha256-modp2048"},
|
|
{"esp_proposal", "aes256-sha256"},
|
|
{"dpd_action", "restart"},
|
|
{"local_id", "@vpn-local"},
|
|
{"remote_id", "@vpn-remote"},
|
|
{"pfs_group", "modp2048"},
|
|
}
|
|
for _, d := range defaults {
|
|
if got := service.Str(cfg, d.key); got != d.expected {
|
|
t.Errorf("%s: got %q, want %q", d.key, got, d.expected)
|
|
}
|
|
}
|
|
if service.Num(cfg, "ike_lifetime", 0) != 86400 {
|
|
t.Errorf("ike_lifetime: got %v, want 86400", cfg["ike_lifetime"])
|
|
}
|
|
}
|
|
|
|
func TestValidateRejectsInvalid(t *testing.T) {
|
|
s := New()
|
|
cases := []struct {
|
|
name string
|
|
cfg map[string]interface{}
|
|
}{
|
|
{"missing remote_gateway", map[string]interface{}{
|
|
"local_subnets": "10.0.0.0/24", "remote_subnets": "10.1.0.0/24",
|
|
}},
|
|
{"missing local_subnets", map[string]interface{}{
|
|
"remote_gateway": "1.2.3.4", "remote_subnets": "10.1.0.0/24",
|
|
}},
|
|
{"missing remote_subnets", map[string]interface{}{
|
|
"remote_gateway": "1.2.3.4", "local_subnets": "10.0.0.0/24",
|
|
}},
|
|
{"invalid gateway", map[string]interface{}{
|
|
"remote_gateway": "not a gateway{}", "local_subnets": "10.0.0.0/24", "remote_subnets": "10.1.0.0/24",
|
|
}},
|
|
{"invalid local_subnets", map[string]interface{}{
|
|
"remote_gateway": "1.2.3.4", "local_subnets": "bad-cidr", "remote_subnets": "10.1.0.0/24",
|
|
}},
|
|
{"invalid remote_subnets", map[string]interface{}{
|
|
"remote_gateway": "1.2.3.4", "local_subnets": "10.0.0.0/24", "remote_subnets": "nope",
|
|
}},
|
|
{"overlapping subnets", map[string]interface{}{
|
|
"remote_gateway": "1.2.3.4", "local_subnets": "10.0.0.0/24", "remote_subnets": "10.0.0.0/24",
|
|
}},
|
|
}
|
|
for _, tc := range cases {
|
|
if _, err := s.Validate(tc.cfg); err == nil {
|
|
t.Errorf("%s: expected error, got nil", tc.name)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestVendorTemplates(t *testing.T) {
|
|
templates := Templates()
|
|
if len(templates) == 0 {
|
|
t.Fatal("Templates() returned empty slice")
|
|
}
|
|
for _, tmpl := range templates {
|
|
if tmpl.Key == "" || tmpl.Name == "" {
|
|
t.Errorf("template missing key/name: %#v", tmpl)
|
|
}
|
|
// Validate with vendor_template should fill in template values
|
|
cfg, err := New().Validate(map[string]interface{}{
|
|
"remote_gateway": "1.2.3.4",
|
|
"local_subnets": "10.0.0.0/24",
|
|
"remote_subnets": "10.1.0.0/24",
|
|
"vendor_template": tmpl.Key,
|
|
})
|
|
if err != nil {
|
|
t.Errorf("template %q: Validate failed: %v", tmpl.Key, err)
|
|
continue
|
|
}
|
|
if service.Str(cfg, "ike_version") != tmpl.IKEVersion {
|
|
t.Errorf("template %q: ike_version %q != %q", tmpl.Key, service.Str(cfg, "ike_version"), tmpl.IKEVersion)
|
|
}
|
|
if service.Str(cfg, "ike_proposal") != tmpl.IKEProposal {
|
|
t.Errorf("template %q: ike_proposal %q != %q", tmpl.Key, service.Str(cfg, "ike_proposal"), tmpl.IKEProposal)
|
|
}
|
|
if service.Str(cfg, "esp_proposal") != tmpl.ESPProposal {
|
|
t.Errorf("template %q: esp_proposal %q != %q", tmpl.Key, service.Str(cfg, "esp_proposal"), tmpl.ESPProposal)
|
|
}
|
|
if service.Str(cfg, "dpd_action") != tmpl.DPDAction {
|
|
t.Errorf("template %q: dpd_action %q != %q", tmpl.Key, service.Str(cfg, "dpd_action"), tmpl.DPDAction)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestSwanctlConf(t *testing.T) {
|
|
s := New()
|
|
cfg := map[string]interface{}{
|
|
"remote_gateway": "203.0.113.1",
|
|
"local_subnets": "192.168.1.0/24",
|
|
"remote_subnets": "192.168.2.0/24",
|
|
"ike_version": "ikev2",
|
|
"ike_proposal": "aes256-sha256-modp2048",
|
|
"esp_proposal": "aes256-sha256",
|
|
"dpd_action": "restart",
|
|
"local_id": "@vpn-local",
|
|
"remote_id": "@vpn-remote",
|
|
}
|
|
conf := s.swanctlConf(42, cfg, "my-secret-psk")
|
|
expected := []string{
|
|
"tunnel-42",
|
|
"remote_addrs = 203.0.113.1",
|
|
"version = 2",
|
|
"proposals = aes256-sha256-modp2048",
|
|
"id = @vpn-local",
|
|
"id = @vpn-remote",
|
|
"site-42",
|
|
"local_ts = 192.168.1.0/24",
|
|
"remote_ts = 192.168.2.0/24",
|
|
"esp_proposals = aes256-sha256",
|
|
"dpd_action = restart",
|
|
"start_action = start",
|
|
"ike-tunnel-42",
|
|
"my-secret-psk",
|
|
}
|
|
for _, e := range expected {
|
|
if !strings.Contains(conf, e) {
|
|
t.Errorf("swanctlConf missing %q:\n%s", e, conf)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestSwanctlConfVIP(t *testing.T) {
|
|
s := New()
|
|
cfg := map[string]interface{}{
|
|
"remote_gateway": "1.2.3.4",
|
|
"local_subnets": "10.0.0.0/24",
|
|
"remote_subnets": "10.1.0.0/24",
|
|
"local_id": "@local",
|
|
"remote_id": "@remote",
|
|
"local_ts_vip": "10.255.0.1",
|
|
}
|
|
conf := s.swanctlConf(1, cfg, "psk")
|
|
if !strings.Contains(conf, "vips = 10.255.0.1") {
|
|
t.Errorf("swanctlConf should include vips when local_ts_vip is set:\n%s", conf)
|
|
}
|
|
}
|
|
|
|
func TestPeerReference(t *testing.T) {
|
|
s := New()
|
|
cfg := map[string]interface{}{
|
|
"remote_gateway": "203.0.113.1",
|
|
"ike_version": "ikev2",
|
|
"ike_proposal": "aes256-sha256-modp2048",
|
|
"esp_proposal": "aes256-sha256",
|
|
"local_id": "@vpn-local",
|
|
"remote_id": "@vpn-remote",
|
|
"local_subnets": "192.168.1.0/24",
|
|
"remote_subnets": "192.168.2.0/24",
|
|
"pfs_group": "modp2048",
|
|
"dpd_action": "restart",
|
|
"public_endpoint": "198.51.100.1",
|
|
}
|
|
ref := s.PeerReference(cfg)
|
|
for _, expected := range []string{
|
|
"198.51.100.1",
|
|
"203.0.113.1",
|
|
"ikev2",
|
|
"aes256-sha256-modp2048",
|
|
"@vpn-local",
|
|
"@vpn-remote",
|
|
"192.168.1.0/24",
|
|
"192.168.2.0/24",
|
|
"modp2048",
|
|
"restart",
|
|
} {
|
|
if !strings.Contains(ref, expected) {
|
|
t.Errorf("PeerReference missing %q:\n%s", expected, ref)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestComparePeerParams(t *testing.T) {
|
|
local := map[string]interface{}{
|
|
"ike_version": "ikev2",
|
|
"ike_proposal": "aes256-sha256-modp2048",
|
|
"esp_proposal": "aes256-sha256",
|
|
"pfs_group": "modp2048",
|
|
"local_subnets": "192.168.1.0/24",
|
|
"remote_subnets": "192.168.2.0/24",
|
|
}
|
|
// Matching peer — no diffs expected
|
|
peer := map[string]interface{}{
|
|
"ike_version": "ikev2",
|
|
"ike_proposal": "aes256-sha256-modp2048",
|
|
"esp_proposal": "aes256-sha256",
|
|
"pfs_group": "modp2048",
|
|
"local_subnets": "192.168.2.0/24",
|
|
}
|
|
diffs := ComparePeerParams(local, peer)
|
|
if len(diffs) != 0 {
|
|
t.Errorf("expected no diffs, got %v", diffs)
|
|
}
|
|
|
|
// Mismatching peer — should detect diffs
|
|
peerBad := map[string]interface{}{
|
|
"ike_version": "ikev1",
|
|
"ike_proposal": "aes128-sha1-modp1024",
|
|
"esp_proposal": "aes128-sha1",
|
|
"pfs_group": "modp1024",
|
|
"local_subnets": "10.0.0.0/8",
|
|
}
|
|
diffs = ComparePeerParams(local, peerBad)
|
|
if len(diffs) < 3 {
|
|
t.Errorf("expected multiple diffs, got %d: %v", len(diffs), diffs)
|
|
}
|
|
// Verify cross-subnet mismatch is detected
|
|
found := false
|
|
for _, d := range diffs {
|
|
if strings.Contains(d, "网段交叉不匹配") || strings.Contains(d, "cross") {
|
|
found = true
|
|
}
|
|
}
|
|
if !found {
|
|
t.Errorf("expected subnet cross-mismatch in diffs: %v", diffs)
|
|
}
|
|
}
|