/
encrypt_status.go
153 lines (136 loc) · 3.69 KB
/
encrypt_status.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
// SPDX-License-Identifier: Apache-2.0
// Copyright 2021 Authors of Cilium
package cmd
import (
"fmt"
"os/exec"
"reflect"
"regexp"
"strings"
"github.com/cilium/cilium/api/v1/client/daemon"
"github.com/cilium/cilium/api/v1/models"
"github.com/cilium/cilium/pkg/command"
"github.com/cilium/cilium/pkg/common"
"github.com/prometheus/procfs"
"github.com/vishvananda/netlink"
"github.com/spf13/cobra"
)
const (
// Cilium uses reqid 1 to tie the IPsec security policies to their matching state
ciliumReqId = "1"
)
type void struct{}
var (
voidType void
countErrors int
regex = regexp.MustCompile("oseq[[:blank:]](0[xX][[:xdigit:]]+)?")
)
var encryptStatusCmd = &cobra.Command{
Use: "status",
Short: "Display the current encryption state",
Run: func(cmd *cobra.Command, args []string) {
common.RequireRootPrivilege("cilium encrypt status")
getEncryptionMode()
},
}
func init() {
encryptCmd.AddCommand(encryptStatusCmd)
command.AddJSONOutput(encryptStatusCmd)
}
func getXfrmStats(mountPoint string) (int, map[string]int) {
fs, err := procfs.NewDefaultFS()
if mountPoint != "" {
fs, err = procfs.NewFS(mountPoint)
}
if err != nil {
Fatalf("Cannot get a new proc FS: %s", err)
}
stats, err := fs.NewXfrmStat()
if err != nil {
Fatalf("Failed to read xfrm statistics: %s", err)
}
v := reflect.ValueOf(stats)
errorMap := make(map[string]int)
if v.Type().Kind() == reflect.Struct {
for i := 0; i < v.NumField(); i++ {
name := v.Type().Field(i).Name
value := v.Field(i).Interface().(int)
if value != 0 {
countErrors += value
errorMap[name] = value
}
}
}
return countErrors, errorMap
}
func countUniqueIPsecKeys() int {
// trying to mimic set type data structure
// using void data type as struct{} because it does not use any memory
keys := make(map[string]void)
xfrmStates, err := netlink.XfrmStateList(netlink.FAMILY_ALL)
if err != nil {
Fatalf("Cannot get xfrm state: %s", err)
}
for _, v := range xfrmStates {
keys[string(v.Aead.Key)] = voidType
}
return len(keys)
}
func maxSequenceNumber() string {
maxSeqNum := "0"
out, err := exec.Command("ip", "xfrm", "state", "list", "reqid", ciliumReqId).Output()
if err != nil {
Fatalf("Cannot get xfrm states: %s", err)
}
commandOutput := string(out)
lines := strings.Split(commandOutput, "\n")
for _, line := range lines {
matched := regex.FindStringSubmatchIndex(line)
if matched != nil {
oseq := line[matched[2]:matched[3]]
if oseq > maxSeqNum {
maxSeqNum = oseq
}
}
}
if maxSeqNum == "0" {
return "N/A"
}
return fmt.Sprintf("%s/0xffffffff", maxSeqNum)
}
func getEncryptionMode() {
params := daemon.NewGetHealthzParamsWithTimeout(timeout)
params.SetBrief(&brief)
resp, err := client.Daemon.GetHealthz(params)
if err != nil {
Fatalf("Cannot get daemon encryption status: %s", err)
}
encryptionStatusResponse := resp.Payload.Encryption
fmt.Printf("Encryption: %-26s\n", encryptionStatusResponse.Mode)
switch encryptionStatusResponse.Mode {
case models.EncryptionStatusModeIPsec:
dumpIPsecStatus()
case models.EncryptionStatusModeWireguard:
dumpWireGuardStatus(encryptionStatusResponse)
}
}
func dumpIPsecStatus() {
keys := countUniqueIPsecKeys()
oseq := maxSequenceNumber()
fmt.Printf("Keys in use: %-26d\n", keys)
fmt.Printf("Max Seq. Number: %s\n", oseq)
errCount, errMap := getXfrmStats("")
fmt.Printf("Errors: %-26d\n", errCount)
if errCount != 0 {
for k, v := range errMap {
fmt.Printf("\t%s: %-26d\n", k, v)
}
}
}
func dumpWireGuardStatus(p *models.EncryptionStatus) {
for _, wg := range p.Wireguard.Interfaces {
fmt.Printf("Interface: %s\n", wg.Name)
fmt.Printf("\tPublic key: %s\n", wg.PublicKey)
fmt.Printf("\tNumber of peers: %d\n", wg.PeerCount)
}
}