mirror of
https://github.com/kubenetworks/kubevpn.git
synced 2025-12-24 11:51:13 +08:00
Compare commits
29 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
51515607dc | ||
|
|
a69ed17fe1 | ||
|
|
4f0da2803f | ||
|
|
cebd3f7623 | ||
|
|
a2f6c26101 | ||
|
|
a27f9d6779 | ||
|
|
cee42b2900 | ||
|
|
1c55e92e1a | ||
|
|
39d3bfe29e | ||
|
|
4e7f0eb901 | ||
|
|
b2bb9cc041 | ||
|
|
e2f096023b | ||
|
|
c6e3937f8b | ||
|
|
c7ba43558e | ||
|
|
f0780cf3ce | ||
|
|
5b240473d1 | ||
|
|
7fe3c29265 | ||
|
|
bd2c2617ee | ||
|
|
0666313b73 | ||
|
|
399950b8be | ||
|
|
2548e494b3 | ||
|
|
04af3deb0d | ||
|
|
457649aa4f | ||
|
|
9c75cf87a4 | ||
|
|
4fdb515e04 | ||
|
|
05f235617f | ||
|
|
f891cc1745 | ||
|
|
c9c85700de | ||
|
|
9f477e0806 |
45
.github/workflows/release.yml
vendored
45
.github/workflows/release.yml
vendored
@@ -26,8 +26,8 @@ jobs:
|
||||
release_name: Release ${{ github.ref }}
|
||||
body: |
|
||||
Changes in this Release
|
||||
- First Change
|
||||
- Second Change
|
||||
- Fix known bugs
|
||||
- Optimize code
|
||||
draft: false
|
||||
prerelease: false
|
||||
|
||||
@@ -48,38 +48,15 @@ jobs:
|
||||
with:
|
||||
name: UPLOAD_URL
|
||||
path: UPLOAD_URL
|
||||
- name: Build kubevpn-linux
|
||||
run: make kubevpn-linux
|
||||
- name: Upload Release Asset
|
||||
uses: actions/upload-release-asset@v1
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
with:
|
||||
upload_url: ${{ steps.create_release.outputs.upload_url }}
|
||||
asset_path: kubevpn
|
||||
asset_name: kubevpn-linux-amd64
|
||||
asset_content_type: application/octet-stream
|
||||
|
||||
- name: Build kubevpn-macos
|
||||
run: make kubevpn-macos
|
||||
- name: Upload Release Asset
|
||||
uses: actions/upload-release-asset@v1
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
with:
|
||||
upload_url: ${{ steps.create_release.outputs.upload_url }}
|
||||
asset_path: kubevpn
|
||||
asset_name: kubevpn-darwin-amd64
|
||||
asset_content_type: application/octet-stream
|
||||
- name: Push image to docker hub
|
||||
run: |
|
||||
echo ${{ secrets.DOCKER_PASSWORD }} | docker login -u ${{ secrets.DOCKER_USER }} --password-stdin
|
||||
make all-image
|
||||
|
||||
- name: Build kubevpn-windows
|
||||
run: make kubevpn-windows
|
||||
- name: Upload Release Asset
|
||||
uses: actions/upload-release-asset@v1
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
- name: Repository Dispatch
|
||||
uses: peter-evans/repository-dispatch@v1
|
||||
with:
|
||||
upload_url: ${{ steps.create_release.outputs.upload_url }}
|
||||
asset_path: kubevpn.exe
|
||||
asset_name: kubevpn-windows-amd64.exe
|
||||
asset_content_type: application/octet-stream
|
||||
token: ${{ secrets.REPOSITORYDISPATCH }}
|
||||
event-type: release-event
|
||||
client-payload: '{"url": "${{ steps.create_release.outputs.upload_url }}", "tag": "${{ github.ref }}"}'
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
name: Go
|
||||
name: Test
|
||||
|
||||
on:
|
||||
push:
|
||||
@@ -31,7 +31,7 @@ jobs:
|
||||
run: kubectl apply -f https://raw.githubusercontent.com/wencaiwulue/kubevpn/master/samples/bookinfo.yaml
|
||||
|
||||
- name: Build
|
||||
run: make kubevpn-linux
|
||||
run: make kubevpn-linux-amd64
|
||||
|
||||
- name: Wait for pods reviews to be ready
|
||||
run: |
|
||||
@@ -54,26 +54,33 @@ jobs:
|
||||
with:
|
||||
go-version: 1.17
|
||||
- uses: docker-practice/actions-setup-docker@master
|
||||
- run: |
|
||||
- name: Pull image in advance
|
||||
run: |
|
||||
rm '/usr/local/bin/kubectl'
|
||||
set -x
|
||||
docker version
|
||||
docker pull naison/kubevpn:v2
|
||||
docker pull naison/kubevpnmesh:v2
|
||||
docker run --rm hello-world
|
||||
- run: |
|
||||
|
||||
- name: Install minikube
|
||||
run: |
|
||||
brew install minikube
|
||||
minikube start --driver=docker
|
||||
kubectl get po -A
|
||||
minikube kubectl -- get po -A
|
||||
|
||||
- name: Kubernetes info
|
||||
run: |
|
||||
kubectl cluster-info
|
||||
cat ~/.kube/config
|
||||
kubectl get pods -n kube-system -o wide
|
||||
|
||||
- name: Install demo bookinfo
|
||||
run: kubectl apply -f https://raw.githubusercontent.com/wencaiwulue/kubevpn/master/samples/bookinfo.yaml
|
||||
|
||||
- name: Build
|
||||
run: make kubevpn-macos
|
||||
run: make kubevpn-darwin-amd64
|
||||
|
||||
- name: Wait for pods reviews to be ready
|
||||
run: |
|
||||
@@ -81,6 +88,7 @@ jobs:
|
||||
kubectl get all -o wide
|
||||
kubectl get nodes -o yaml
|
||||
ifconfig
|
||||
netstat -anr
|
||||
|
||||
- name: Test
|
||||
run: go test -v ./test/
|
||||
@@ -94,13 +102,14 @@ jobs:
|
||||
# uses: actions/setup-go@v2
|
||||
# with:
|
||||
# go-version: 1.17
|
||||
# - uses: docker-practice/actions-setup-docker@master
|
||||
# # - run: |
|
||||
# # choco install docker-desktop
|
||||
# # docker version
|
||||
# # docker run --rm hello-world
|
||||
# - run: |
|
||||
# docker version
|
||||
# docker run --rm hello-world
|
||||
# - run: |
|
||||
# winget install minikube
|
||||
# minikube start --driver=docker
|
||||
# choco install virtualbox
|
||||
# choco install minikube
|
||||
# minikube start --driver=virtualbox
|
||||
# minikube kubectl -- get po -A
|
||||
# choco install make
|
||||
# - name: Kubernetes info
|
||||
44
.github/workflows/upload_release.yml
vendored
Normal file
44
.github/workflows/upload_release.yml
vendored
Normal file
@@ -0,0 +1,44 @@
|
||||
name: Upload release
|
||||
|
||||
on:
|
||||
repository_dispatch:
|
||||
types: [ release-event ]
|
||||
|
||||
jobs:
|
||||
build:
|
||||
name: Create Release
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
os-arch: [
|
||||
kubevpn-darwin-amd64,
|
||||
kubevpn-darwin-arm64,
|
||||
kubevpn-windows-amd64.exe,
|
||||
kubevpn-windows-arm64.exe,
|
||||
kubevpn-windows-386.exe,
|
||||
kubevpn-linux-amd64,
|
||||
kubevpn-linux-arm64,
|
||||
kubevpn-linux-386,
|
||||
]
|
||||
steps:
|
||||
- name: Set up Go
|
||||
uses: actions/setup-go@v2
|
||||
with:
|
||||
go-version: 1.17
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v2
|
||||
|
||||
- name: Build kubevpn-all-arch
|
||||
run: |
|
||||
git tag ${{ github.event.client_payload.tag }} || true
|
||||
make all-kubevpn
|
||||
|
||||
- name: Upload Release Asset
|
||||
uses: actions/upload-release-asset@v1
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
with:
|
||||
upload_url: ${{ github.event.client_payload.url }}
|
||||
asset_path: ${{ matrix.os-arch }}
|
||||
asset_name: ${{ matrix.os-arch }}
|
||||
asset_content_type: application/octet-stream
|
||||
103
Makefile
103
Makefile
@@ -1,37 +1,96 @@
|
||||
.PHONY: kubevpn-macos
|
||||
kubevpn-macos:
|
||||
go build -o kubevpn github.com/wencaiwulue/kubevpn/cmd/kubevpn
|
||||
chmod +x kubevpn
|
||||
cp kubevpn /usr/local/bin/kubevpn
|
||||
# These are the values we want to pass for VERSION and BUILD
|
||||
VERSION := $(shell git tag -l --sort=v:refname | tail -1)
|
||||
GIT_COMMIT := $(shell git describe --match=NeVeRmAtCh --always --abbrev=40)
|
||||
BUILD_TIME := $(shell date +"%Y-%m-%dT%H:%M:%SZ")
|
||||
BRANCH := $(shell git rev-parse --abbrev-ref HEAD)
|
||||
|
||||
.PHONY: kubevpn-windows
|
||||
kubevpn-windows:
|
||||
CGO_ENABLED=0 GOOS=windows GOARCH=amd64 go build -o kubevpn.exe github.com/wencaiwulue/kubevpn/cmd/kubevpn
|
||||
GOOS := $(shell go env GOHOSTOS)
|
||||
GOARCH := $(shell go env GOHOSTARCH)
|
||||
TARGET := kubevpn-${GOOS}-${GOARCH}
|
||||
OS_ARCH := ${GOOS}/${GOARCH}
|
||||
|
||||
.PHONY: kubevpn-linux
|
||||
kubevpn-linux:
|
||||
CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -o kubevpn github.com/wencaiwulue/kubevpn/cmd/kubevpn
|
||||
chmod +x kubevpn
|
||||
cp kubevpn /usr/local/bin/kubevpn
|
||||
FOLDER := github.com/wencaiwulue/kubevpn/cmd/kubevpn
|
||||
CONTROL_PLANE_FOLDER := github.com/wencaiwulue/kubevpn/pkg/controlplane/cmd/server
|
||||
|
||||
.PHONY: control-plane-linux
|
||||
control-plane-linux:
|
||||
CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -o envoy-xds-server github.com/wencaiwulue/kubevpn/pkg/controlplane/cmd/server
|
||||
chmod +x envoy-xds-server
|
||||
# Setup the -ldflags option for go build here, interpolate the variable values
|
||||
LDFLAGS=--ldflags "-w -s \
|
||||
-X ${FOLDER}/cmds.Version=${VERSION} \
|
||||
-X ${FOLDER}/cmds.BuildTime=${BUILD_TIME} \
|
||||
-X ${FOLDER}/cmds.GitCommit=${GIT_COMMIT} \
|
||||
-X ${FOLDER}/cmds.Branch=${BRANCH} \
|
||||
-X ${FOLDER}/cmds.OsArch=${OS_ARCH} \
|
||||
"
|
||||
|
||||
.PHONY: all
|
||||
all: all-kubevpn all-image
|
||||
|
||||
.PHONY: all-kubevpn
|
||||
all-kubevpn: kubevpn-darwin-amd64 kubevpn-darwin-arm64 \
|
||||
kubevpn-windows-amd64 kubevpn-windows-386 kubevpn-windows-arm64 \
|
||||
kubevpn-linux-amd64 kubevpn-linux-386 kubevpn-linux-arm64
|
||||
|
||||
.PHONY: all-image
|
||||
all-image: image image-mesh image-control-plane
|
||||
|
||||
# ---------darwin-----------
|
||||
.PHONY: kubevpn-darwin-amd64
|
||||
kubevpn-darwin-amd64:
|
||||
CGO_ENABLED=0 GOOS=darwin GOARCH=amd64 go build ${LDFLAGS} -o kubevpn-darwin-amd64 ${FOLDER}
|
||||
chmod +x kubevpn-darwin-amd64
|
||||
cp kubevpn-darwin-amd64 /usr/local/bin/kubevpn
|
||||
.PHONY: kubevpn-darwin-arm64
|
||||
kubevpn-darwin-arm64:
|
||||
CGO_ENABLED=0 GOOS=darwin GOARCH=arm64 go build ${LDFLAGS} -o kubevpn-darwin-arm64 ${FOLDER}
|
||||
chmod +x kubevpn-darwin-arm64
|
||||
cp kubevpn-darwin-arm64 /usr/local/bin/kubevpn
|
||||
# ---------darwin-----------
|
||||
|
||||
# ---------windows-----------
|
||||
.PHONY: kubevpn-windows-amd64
|
||||
kubevpn-windows-amd64:
|
||||
CGO_ENABLED=0 GOOS=windows GOARCH=amd64 go build ${LDFLAGS} -o kubevpn-windows-amd64.exe ${FOLDER}
|
||||
.PHONY: kubevpn-windows-arm64
|
||||
kubevpn-windows-arm64:
|
||||
CGO_ENABLED=0 GOOS=windows GOARCH=arm64 go build ${LDFLAGS} -o kubevpn-windows-arm64.exe ${FOLDER}
|
||||
.PHONY: kubevpn-windows-386
|
||||
kubevpn-windows-386:
|
||||
CGO_ENABLED=0 GOOS=windows GOARCH=386 go build ${LDFLAGS} -o kubevpn-windows-386.exe ${FOLDER}
|
||||
# ---------windows-----------
|
||||
|
||||
# ---------linux-----------
|
||||
.PHONY: kubevpn-linux-amd64
|
||||
kubevpn-linux-amd64:
|
||||
CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build ${LDFLAGS} -o kubevpn-linux-amd64 ${FOLDER}
|
||||
chmod +x kubevpn-linux-amd64
|
||||
cp kubevpn-linux-amd64 /usr/local/bin/kubevpn
|
||||
.PHONY: kubevpn-linux-arm64
|
||||
kubevpn-linux-arm64:
|
||||
CGO_ENABLED=0 GOOS=linux GOARCH=arm64 go build ${LDFLAGS} -o kubevpn-linux-arm64 ${FOLDER}
|
||||
chmod +x kubevpn-linux-arm64
|
||||
cp kubevpn-linux-arm64 /usr/local/bin/kubevpn
|
||||
.PHONY: kubevpn-linux-386
|
||||
kubevpn-linux-386:
|
||||
CGO_ENABLED=0 GOOS=linux GOARCH=386 go build ${LDFLAGS} -o kubevpn-linux-386 ${FOLDER}
|
||||
chmod +x kubevpn-linux-386
|
||||
cp kubevpn-linux-386 /usr/local/bin/kubevpn
|
||||
# ---------linux-----------
|
||||
|
||||
.PHONY: image
|
||||
image: kubevpn-linux
|
||||
image: kubevpn-linux-amd64
|
||||
mv kubevpn-linux-amd64 kubevpn
|
||||
docker build -t naison/kubevpn:v2 -f ./dockerfile/server/Dockerfile .
|
||||
rm -fr kubevpn
|
||||
docker push naison/kubevpn:v2
|
||||
|
||||
.PHONY: image_mesh
|
||||
image_mesh:
|
||||
.PHONY: image-mesh
|
||||
image-mesh:
|
||||
docker build -t naison/kubevpnmesh:v2 -f ./dockerfile/mesh/Dockerfile .
|
||||
docker push naison/kubevpnmesh:v2
|
||||
|
||||
.PHONY: image_control_plane
|
||||
image_control_plane: control-plane-linux
|
||||
.PHONY: image-control-plane
|
||||
image-control-plane:
|
||||
CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -o envoy-xds-server ${CONTROL_PLANE_FOLDER}
|
||||
chmod +x envoy-xds-server
|
||||
docker build -t naison/envoy-xds-server:latest -f ./dockerfile/controlplane/Dockerfile .
|
||||
rm -fr envoy-xds-server
|
||||
docker push naison/envoy-xds-server:latest
|
||||
|
||||
10
README.md
10
README.md
@@ -10,9 +10,9 @@ kubernetes cluster service can also access your local service
|
||||
```shell
|
||||
git clone https://github.com/wencaiwulue/kubevpn.git
|
||||
cd kubevpn
|
||||
make kubevpn-linux
|
||||
make kubevpn-macos
|
||||
make kubevpn-windows
|
||||
make kubevpn-linux-amd64
|
||||
make kubevpn-darwin-amd64
|
||||
make kubevpn-windows-amd64
|
||||
```
|
||||
|
||||
if you are using windows, you can build by this command:
|
||||
@@ -156,7 +156,7 @@ func main() {
|
||||
http.HandleFunc("/", func(writer http.ResponseWriter, request *http.Request) {
|
||||
_, _ = io.WriteString(writer, "Hello world!")
|
||||
})
|
||||
_ = http.ListenAndServe(":8080", nil)
|
||||
_ = http.ListenAndServe(":9080", nil)
|
||||
}
|
||||
```
|
||||
|
||||
@@ -222,4 +222,4 @@ Hello world!%
|
||||
|
||||
on Windows platform, you need to
|
||||
install [PowerShell](https://docs.microsoft.com/en-us/powershell/scripting/install/installing-powershell-on-windows?view=powershell-7.2)
|
||||
in advance
|
||||
in advance
|
||||
|
||||
@@ -9,9 +9,9 @@
|
||||
```shell
|
||||
git clone https://github.com/wencaiwulue/kubevpn.git
|
||||
cd kubevpn
|
||||
make kubevpn-linux
|
||||
make kubevpn-macos
|
||||
make kubevpn-windows
|
||||
make kubevpn-linux-amd64
|
||||
make kubevpn-darwin-amd64
|
||||
make kubevpn-windows-amd64
|
||||
```
|
||||
|
||||
如果你在使用 Windows 系统,可以使用下面这条命令构建:
|
||||
|
||||
6
TODO.MD
6
TODO.MD
@@ -11,14 +11,14 @@
|
||||
- [ ] 考虑是否需要把 openvpn tap/tun 驱动作为后备方案
|
||||
- [x] 加入 TLS 以提高安全性
|
||||
- [ ] 写个 CNI 网络插件,直接提供 VPN 功能
|
||||
- [ ] 优化重连逻辑
|
||||
- [x] 优化重连逻辑
|
||||
- [x] 支持 service mesh
|
||||
- [ ] service mesh 支持多端口
|
||||
- [x] 使用自己写的 proxy 替换 envoy
|
||||
- [ ] 优化性能,Windows 上考虑使用 IPC 通信
|
||||
- [x] 自己写个 control plane
|
||||
- [ ] 考虑是否将 control plane 和服务分开
|
||||
- [ ] 写单元测试,优化 GitHub action
|
||||
- [x] 写单元测试,优化 GitHub action
|
||||
- [ ] Linux 和 macOS 也改用 WireGuard library
|
||||
- [ ] 探测是否有重复路由的 utun设备,禁用 `sudo ifconfig utun1 down`
|
||||
- [x] 探测是否有重复路由的 utun设备,禁用 `sudo ifconfig utun1 down`
|
||||
|
||||
|
||||
@@ -29,6 +29,12 @@ var connectCmd = &cobra.Command{
|
||||
Use: "connect",
|
||||
Short: "connect",
|
||||
Long: `connect`,
|
||||
PersistentPreRun: func(cmd *cobra.Command, args []string) {
|
||||
if !util.IsAdmin() {
|
||||
util.RunWithElevated()
|
||||
os.Exit(0)
|
||||
}
|
||||
},
|
||||
PreRun: func(*cobra.Command, []string) {
|
||||
util.InitLogger(util.Debug)
|
||||
if util.IsWindows() {
|
||||
|
||||
51
cmd/kubevpn/cmds/version.go
Normal file
51
cmd/kubevpn/cmds/version.go
Normal file
@@ -0,0 +1,51 @@
|
||||
package cmds
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/spf13/cobra"
|
||||
"runtime"
|
||||
"runtime/debug"
|
||||
"time"
|
||||
)
|
||||
|
||||
// --ldflags -X
|
||||
var (
|
||||
Version = ""
|
||||
OsArch = ""
|
||||
GitCommit = ""
|
||||
BuildTime = ""
|
||||
Branch = ""
|
||||
)
|
||||
|
||||
func reformatDate(buildTime string) string {
|
||||
t, errTime := time.Parse(time.RFC3339Nano, buildTime)
|
||||
if errTime == nil {
|
||||
return t.Format("2006-01-02 15:04:05")
|
||||
}
|
||||
return buildTime
|
||||
}
|
||||
|
||||
var versionCmd = &cobra.Command{
|
||||
Use: "version",
|
||||
Short: "Print the version number of KubeVPN",
|
||||
Long: `This is the version of KubeVPN`,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
fmt.Printf("KubeVPN: CLI\n")
|
||||
fmt.Printf(" Version: %s\n", Version)
|
||||
fmt.Printf(" Branch: %s\n", Branch)
|
||||
fmt.Printf(" Git commit: %s\n", GitCommit)
|
||||
fmt.Printf(" Built time: %s\n", reformatDate(BuildTime))
|
||||
fmt.Printf(" Built OS/Arch: %s\n", OsArch)
|
||||
fmt.Printf(" Built Go version: %s\n", runtime.Version())
|
||||
},
|
||||
}
|
||||
|
||||
func init() {
|
||||
RootCmd.AddCommand(versionCmd)
|
||||
// Prefer version number inserted at build using --ldflags
|
||||
if Version == "" {
|
||||
if i, ok := debug.ReadBuildInfo(); ok {
|
||||
Version = i.Main.Version
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3,18 +3,13 @@ package main
|
||||
import (
|
||||
log "github.com/sirupsen/logrus"
|
||||
"github.com/wencaiwulue/kubevpn/cmd/kubevpn/cmds"
|
||||
"github.com/wencaiwulue/kubevpn/util"
|
||||
"net/http"
|
||||
_ "net/http/pprof"
|
||||
)
|
||||
|
||||
func main() {
|
||||
if !util.IsAdmin() {
|
||||
util.RunWithElevated()
|
||||
} else {
|
||||
go func() {
|
||||
log.Println(http.ListenAndServe("localhost:6060", nil))
|
||||
}()
|
||||
_ = cmds.RootCmd.Execute()
|
||||
}
|
||||
go func() {
|
||||
log.Println(http.ListenAndServe("localhost:6060", nil))
|
||||
}()
|
||||
_ = cmds.RootCmd.Execute()
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@ import (
|
||||
log "github.com/sirupsen/logrus"
|
||||
"k8s.io/apimachinery/pkg/util/cache"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
type server struct {
|
||||
@@ -44,7 +45,9 @@ func (s *server) ServeDNS(w miekgdns.ResponseWriter, r *miekgdns.Msg) {
|
||||
case 5:
|
||||
}
|
||||
r.Question = []miekgdns.Question{question}
|
||||
answer, err := miekgdns.Exchange(r, s.forwardDNS.Servers[0]+":53")
|
||||
client := miekgdns.Client{Net: "udp", Timeout: time.Second * 5}
|
||||
answer, _, err := client.Exchange(r, s.forwardDNS.Servers[0]+":53")
|
||||
//answer, err := miekgdns.Exchange(r, s.forwardDNS.Servers[0]+":53")
|
||||
if err != nil {
|
||||
log.Warnln(err)
|
||||
err = w.WriteMsg(r)
|
||||
|
||||
@@ -3,4 +3,4 @@ FROM envoyproxy/envoy-dev:5f7d6efb5786ee3de31b1fb37c78fa281718b704
|
||||
WORKDIR /app
|
||||
RUN sed -i s@/security.ubuntu.com/@/mirrors.aliyun.com/@g /etc/apt/sources.list \
|
||||
&& sed -i s@/archive.ubuntu.com/@/mirrors.aliyun.com/@g /etc/apt/sources.list
|
||||
RUN apt-get clean && apt-get update && apt-get install -y wget dnsutils vim curl net-tools iptables iputils-ping lsof iproute2
|
||||
RUN apt-get clean && apt-get update && apt-get install -y wget dnsutils vim curl net-tools iptables iputils-ping lsof iproute2 tcpdump
|
||||
@@ -2,5 +2,5 @@ FROM ubuntu:latest
|
||||
WORKDIR /app
|
||||
RUN sed -i s@/security.ubuntu.com/@/mirrors.aliyun.com/@g /etc/apt/sources.list \
|
||||
&& sed -i s@/archive.ubuntu.com/@/mirrors.aliyun.com/@g /etc/apt/sources.list
|
||||
RUN apt-get clean && apt-get update && apt-get install -y wget dnsutils vim curl net-tools iptables iputils-ping lsof iproute2
|
||||
RUN apt-get clean && apt-get update && apt-get install -y wget dnsutils vim curl net-tools iptables iputils-ping lsof iproute2 tcpdump
|
||||
COPY ./kubevpn /usr/local/bin/kubevpn
|
||||
@@ -1,5 +1,6 @@
|
||||
//go:build windows && x86
|
||||
// +build windows,x86
|
||||
//go:build windows && (x86 || 386)
|
||||
// +build windows
|
||||
// +build x86 386
|
||||
|
||||
package wintun
|
||||
|
||||
|
||||
8
go.mod
8
go.mod
@@ -19,8 +19,8 @@ require (
|
||||
github.com/sirupsen/logrus v1.8.1
|
||||
github.com/songgao/water v0.0.0-20200317203138-2b4b6d7c09d8
|
||||
github.com/spf13/cobra v1.1.3
|
||||
golang.org/x/net v0.0.0-20211111083644-e5c967477495
|
||||
golang.org/x/sys v0.0.0-20211110154304-99a53858aa08
|
||||
golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd
|
||||
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e
|
||||
golang.zx2c4.com/wireguard v0.0.0-20211209221555-9c9e7e272434
|
||||
golang.zx2c4.com/wireguard/windows v0.4.10
|
||||
google.golang.org/appengine v1.6.7 // indirect
|
||||
@@ -33,6 +33,7 @@ require (
|
||||
k8s.io/client-go v0.21.2
|
||||
k8s.io/klog/v2 v2.10.0 // indirect
|
||||
k8s.io/kubectl v0.21.2
|
||||
k8s.io/utils v0.0.0-20201110183641-67b214c5f920
|
||||
)
|
||||
|
||||
require (
|
||||
@@ -81,7 +82,7 @@ require (
|
||||
go.starlark.net v0.0.0-20200306205701-8dd3e2ee1dd5 // indirect
|
||||
golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa // indirect
|
||||
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d // indirect
|
||||
golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d // indirect
|
||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 // indirect
|
||||
golang.org/x/text v0.3.7 // indirect
|
||||
golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba // indirect
|
||||
golang.zx2c4.com/wintun v0.0.0-20211104114900-415007cec224 // indirect
|
||||
@@ -90,7 +91,6 @@ require (
|
||||
gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776 // indirect
|
||||
k8s.io/component-base v0.21.2 // indirect
|
||||
k8s.io/kube-openapi v0.0.0-20210305001622-591a79e4bda7 // indirect
|
||||
k8s.io/utils v0.0.0-20201110183641-67b214c5f920 // indirect
|
||||
sigs.k8s.io/kustomize/api v0.8.8 // indirect
|
||||
sigs.k8s.io/kustomize/kyaml v0.10.17 // indirect
|
||||
sigs.k8s.io/structured-merge-diff/v4 v4.1.0 // indirect
|
||||
|
||||
9
go.sum
9
go.sum
@@ -874,8 +874,9 @@ golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v
|
||||
golang.org/x/net v0.0.0-20210224082022-3d97a244fca7/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/net v0.0.0-20210903162142-ad29c8ab022f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20211111083644-e5c967477495 h1:cjxxlQm6d4kYbhpZ2ghvmI8xnq0AG+jXmzrhzfkyu5A=
|
||||
golang.org/x/net v0.0.0-20211111083644-e5c967477495/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd h1:O7DYs+zxREGLKzKoMQrtrEacpb0ZVXA5rIwylE2Xchk=
|
||||
golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
@@ -966,12 +967,14 @@ golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBc
|
||||
golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210906170528-6f6e22806c34/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20211103235746-7861aae1554b/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20211110154304-99a53858aa08 h1:WecRHqgE09JBkh/584XIE6PMz5KKE/vER4izNUi30AQ=
|
||||
golang.org/x/sys v0.0.0-20211110154304-99a53858aa08/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e h1:fLOSk5Q00efkSvAm+4xcoXD+RRmLmmulPn5I3Y9F2EM=
|
||||
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d h1:SZxvLBoTP5yHO3Frd4z4vrF+DBX9vMVanchswa69toE=
|
||||
golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 h1:JGgROgKl9N8DuW20oFS5gxc+lE67/N3FcwmBPMe7ArY=
|
||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
|
||||
@@ -17,6 +17,7 @@ import (
|
||||
cmdutil "k8s.io/kubectl/pkg/cmd/util"
|
||||
"k8s.io/kubectl/pkg/polymorphichelpers"
|
||||
"net"
|
||||
"os"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
@@ -116,6 +117,7 @@ func (c *ConnectOptions) DoConnect() (err error) {
|
||||
return err
|
||||
}
|
||||
c.deleteFirewallRuleAndSetupDNS(ctx)
|
||||
c.detectConflictDevice()
|
||||
return
|
||||
}
|
||||
|
||||
@@ -212,6 +214,16 @@ func (c *ConnectOptions) deleteFirewallRuleAndSetupDNS(ctx context.Context) {
|
||||
log.Info("dns service ok")
|
||||
}
|
||||
|
||||
func (c *ConnectOptions) detectConflictDevice() {
|
||||
tun := os.Getenv("tunName")
|
||||
if len(tun) == 0 {
|
||||
return
|
||||
}
|
||||
if err := DetectAndDisableConflictDevice(tun); err != nil {
|
||||
log.Warnf("error occours while disable conflict devices, err: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func (c *ConnectOptions) setupDNS() {
|
||||
relovConf, err := dns.GetDNSServiceIPFromPod(c.clientset, c.restclient, c.config, util.TrafficManager, c.Namespace)
|
||||
if err != nil {
|
||||
@@ -245,18 +257,18 @@ func getCIDR(clientset *kubernetes.Clientset, namespace string) ([]*net.IPNet, e
|
||||
var CIDRList []*net.IPNet
|
||||
// get pod CIDR from node spec
|
||||
if nodeList, err := clientset.CoreV1().Nodes().List(context.TODO(), metav1.ListOptions{}); err == nil {
|
||||
var podCIDRs = sets.NewString()
|
||||
for _, node := range nodeList.Items {
|
||||
var podCIDRs []string
|
||||
if node.Spec.PodCIDRs != nil {
|
||||
podCIDRs = append(podCIDRs, node.Spec.PodCIDRs...)
|
||||
podCIDRs.Insert(node.Spec.PodCIDRs...)
|
||||
}
|
||||
if len(node.Spec.PodCIDR) != 0 {
|
||||
podCIDRs = append(podCIDRs, node.Spec.PodCIDR)
|
||||
podCIDRs.Insert(node.Spec.PodCIDR)
|
||||
}
|
||||
for _, podCIDR := range podCIDRs {
|
||||
if _, CIDR, err := net.ParseCIDR(podCIDR); err == nil {
|
||||
CIDRList = append(CIDRList, CIDR)
|
||||
}
|
||||
}
|
||||
for _, podCIDR := range podCIDRs.List() {
|
||||
if _, CIDR, err := net.ParseCIDR(podCIDR); err == nil {
|
||||
CIDRList = append(CIDRList, CIDR)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -110,10 +110,10 @@ func UnPatchContainer(factory cmdutil.Factory, clientset *kubernetes.Clientset,
|
||||
return err
|
||||
}
|
||||
|
||||
port := uint32(templateSpec.Spec.Containers[0].Ports[0].ContainerPort)
|
||||
//port := uint32(templateSpec.Spec.Containers[0].Ports[0].ContainerPort)
|
||||
configMapName := fmt.Sprintf("%s-%s", object.Mapping.Resource.Resource, object.Name)
|
||||
|
||||
createEnvoyConfigMapIfNeeded(clientset, object.Namespace, configMapName, strconv.Itoa(int(port)))
|
||||
//createEnvoyConfigMapIfNeeded(clientset, object.Namespace, configMapName, strconv.Itoa(int(port)))
|
||||
err = removeEnvoyConfig(clientset, object.Namespace, configMapName, headers)
|
||||
if err != nil {
|
||||
log.Warnln(err)
|
||||
|
||||
@@ -21,8 +21,15 @@ func RemoveContainers(spec *v1.PodTemplateSpec) {
|
||||
}
|
||||
}
|
||||
for i := 0; i < len(spec.Spec.Containers); i++ {
|
||||
for j := 0; j < len(spec.Spec.Containers[i].VolumeMounts); j++ {
|
||||
if spec.Spec.Containers[i].VolumeMounts[j].Name == EnvoyConfig {
|
||||
spec.Spec.Containers[i].VolumeMounts = append(spec.Spec.Containers[i].VolumeMounts[:j],
|
||||
spec.Spec.Containers[i].VolumeMounts[j+1:]...)
|
||||
}
|
||||
}
|
||||
if sets.NewString(EnvoyProxy, ControlPlane, VPN).Has(spec.Spec.Containers[i].Name) {
|
||||
spec.Spec.Containers = append(spec.Spec.Containers[:i], spec.Spec.Containers[i+1:]...)
|
||||
i--
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -38,6 +45,7 @@ func AddMeshContainer(spec *v1.PodTemplateSpec, configMapName string, c util.Pod
|
||||
for i := 0; i < len(spec.Spec.Containers); i++ {
|
||||
if sets.NewString(EnvoyProxy, ControlPlane, VPN).Has(spec.Spec.Containers[i].Name) {
|
||||
spec.Spec.Containers = append(spec.Spec.Containers[:i], spec.Spec.Containers[i+1:]...)
|
||||
i--
|
||||
}
|
||||
}
|
||||
zero := int64(0)
|
||||
|
||||
56
pkg/network_interface.go
Normal file
56
pkg/network_interface.go
Normal file
@@ -0,0 +1,56 @@
|
||||
package pkg
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
log "github.com/sirupsen/logrus"
|
||||
"k8s.io/apimachinery/pkg/util/sets"
|
||||
"net"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// DetectAndDisableConflictDevice will detect conflict route table and try to disable device
|
||||
// 1, get route table
|
||||
// 2, detect conflict
|
||||
// 3, disable device
|
||||
func DetectAndDisableConflictDevice(origin string) error {
|
||||
routeTable, err := getRouteTable()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
conflict := detectConflictDevice(origin, routeTable)
|
||||
if len(conflict) != 0 {
|
||||
log.Infof("those device: %s will to be disabled because of route conflict with %s", strings.Join(conflict, ","), origin)
|
||||
}
|
||||
err = disableDevice(conflict)
|
||||
return err
|
||||
}
|
||||
|
||||
func detectConflictDevice(origin string, routeTable map[string][]*net.IPNet) []string {
|
||||
var conflict = sets.NewString()
|
||||
vpnRoute := routeTable[origin]
|
||||
for k, originRoute := range routeTable {
|
||||
if k == origin {
|
||||
continue
|
||||
}
|
||||
out:
|
||||
for _, originNet := range originRoute {
|
||||
for _, vpnNet := range vpnRoute {
|
||||
// like 255.255.0.0/16 should not take effect
|
||||
if bytes.Equal(originNet.IP, originNet.Mask) || bytes.Equal(vpnNet.IP, vpnNet.Mask) {
|
||||
continue
|
||||
}
|
||||
if vpnNet.Contains(originNet.IP) || originNet.Contains(vpnNet.IP) {
|
||||
originMask, _ := originNet.Mask.Size()
|
||||
vpnMask, _ := vpnNet.Mask.Size()
|
||||
// means interface: k is more precisely, traffic will go to interface k because route table feature
|
||||
// mare precisely is preferred
|
||||
if originMask > vpnMask {
|
||||
conflict.Insert(k)
|
||||
break out
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return conflict.Delete(origin).List()
|
||||
}
|
||||
156
pkg/network_interface_test.go
Normal file
156
pkg/network_interface_test.go
Normal file
@@ -0,0 +1,156 @@
|
||||
package pkg
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
"syscall"
|
||||
"testing"
|
||||
|
||||
"golang.org/x/net/route"
|
||||
)
|
||||
|
||||
// netstat -anr | grep 10.61
|
||||
//10.61/16 utun4 USc utun4
|
||||
//10.61.10.251 10.176.32.40 UGHWIig utun2
|
||||
//10.61.64/18 10.61.64.1 UCS utun3
|
||||
//10.61.64.1 10.61.64.0 UH utun3
|
||||
func TestConflict(t *testing.T) {
|
||||
var mm = make(map[string][]*net.IPNet)
|
||||
_, ipNet, err := net.ParseCIDR("10.61.0.0/16")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
_, ipNet2, err := net.ParseCIDR("10.61.64.0/18")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
_, ipNet3, err := net.ParseCIDR("10.61.64.1/24")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
mm["utun4"] = []*net.IPNet{ipNet}
|
||||
mm["utun3"] = []*net.IPNet{ipNet2, ipNet3}
|
||||
|
||||
var origin = "utun4"
|
||||
conflict := detectConflictDevice(origin, mm)
|
||||
fmt.Println(conflict)
|
||||
}
|
||||
|
||||
func TestGetConflictDevice(t *testing.T) {
|
||||
err := DetectAndDisableConflictDevice("utun2")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestParse(t *testing.T) {
|
||||
rib, err := route.FetchRIB(syscall.AF_INET, syscall.NET_RT_DUMP, 0)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
msgs, err := route.ParseRIB(syscall.NET_RT_DUMP, rib)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
nameToIndex := make(map[int]string)
|
||||
addrs, err := net.Interfaces()
|
||||
for _, addr := range addrs {
|
||||
nameToIndex[addr.Index] = addr.Name
|
||||
}
|
||||
|
||||
m := make(map[string][]route.Addr)
|
||||
for _, msg := range msgs {
|
||||
message := msg.(*route.RouteMessage)
|
||||
if name, found := nameToIndex[message.Index]; found {
|
||||
if v, ok := m[name]; ok {
|
||||
temp := removeEmptyElement(message)
|
||||
m[name] = append(v, temp...)
|
||||
} else {
|
||||
m[name] = removeEmptyElement(message)
|
||||
}
|
||||
}
|
||||
}
|
||||
fmt.Println(m)
|
||||
}
|
||||
|
||||
func removeEmptyElement(message *route.RouteMessage) []route.Addr {
|
||||
var temp []route.Addr
|
||||
for _, addr := range message.Addrs {
|
||||
if addr != nil {
|
||||
temp = append(temp, addr)
|
||||
}
|
||||
}
|
||||
return temp
|
||||
}
|
||||
|
||||
func TestGetRouteTableByNetstat(t *testing.T) {
|
||||
ip := net.ParseIP("192.168.1.1")
|
||||
for i := range ip.To4() {
|
||||
fmt.Println(i)
|
||||
}
|
||||
}
|
||||
|
||||
func TestInteract(t *testing.T) {
|
||||
type data struct {
|
||||
ipNet1 *net.IPNet
|
||||
ipNet2 *net.IPNet
|
||||
result bool
|
||||
}
|
||||
var list = []data{{
|
||||
ipNet1: &net.IPNet{
|
||||
IP: net.ParseIP("192.168.1.1"),
|
||||
Mask: net.CIDRMask(24, 32),
|
||||
},
|
||||
ipNet2: &net.IPNet{
|
||||
IP: net.ParseIP("192.168.100.100"),
|
||||
Mask: net.CIDRMask(16, 32),
|
||||
},
|
||||
result: true,
|
||||
}, {
|
||||
ipNet1: &net.IPNet{
|
||||
IP: net.ParseIP("192.168.0.0"),
|
||||
Mask: net.CIDRMask(17, 32),
|
||||
},
|
||||
ipNet2: &net.IPNet{
|
||||
IP: net.ParseIP("192.168.0.0"),
|
||||
Mask: net.CIDRMask(16, 32),
|
||||
},
|
||||
result: true,
|
||||
}, {
|
||||
ipNet1: &net.IPNet{
|
||||
IP: net.ParseIP("191.168.0.0"),
|
||||
Mask: net.CIDRMask(17, 32),
|
||||
},
|
||||
ipNet2: &net.IPNet{
|
||||
IP: net.ParseIP("192.168.0.0"),
|
||||
Mask: net.CIDRMask(16, 32),
|
||||
},
|
||||
result: false,
|
||||
}, {
|
||||
ipNet1: &net.IPNet{
|
||||
IP: net.ParseIP("255.255.255.0"),
|
||||
Mask: net.CIDRMask(24, 32),
|
||||
},
|
||||
ipNet2: &net.IPNet{
|
||||
IP: net.ParseIP("255.255.0.0"),
|
||||
Mask: net.CIDRMask(16, 32),
|
||||
},
|
||||
result: true,
|
||||
}, {
|
||||
ipNet1: &net.IPNet{
|
||||
IP: net.ParseIP("255.255.255.255"),
|
||||
Mask: net.CIDRMask(32, 32),
|
||||
},
|
||||
ipNet2: &net.IPNet{
|
||||
IP: net.ParseIP("255.255.0.0"),
|
||||
Mask: net.CIDRMask(16, 32),
|
||||
},
|
||||
result: false,
|
||||
}}
|
||||
for _, d := range list {
|
||||
if b := d.ipNet1.Contains(d.ipNet2.IP) || d.ipNet2.Contains(d.ipNet1.IP); d.result != b {
|
||||
t.FailNow()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -185,7 +185,7 @@ func CreateInboundPod(factory cmdutil.Factory, namespace, workloads string, conf
|
||||
}})
|
||||
_, err = helper.Patch(object.Namespace, object.Name, types.JSONPatchType, bytes, &metav1.PatchOptions{})
|
||||
if err != nil {
|
||||
log.Errorf("error while inject proxy container, err: %v, exiting...")
|
||||
log.Errorf("error while inject proxy container, err: %v, exiting...", err)
|
||||
return err
|
||||
}
|
||||
removePatch, restorePatch := patch(origin, path)
|
||||
|
||||
@@ -247,3 +247,14 @@ func patchs(helper *pkgresource.Helper, namespace, name string, p []byte) (k8sru
|
||||
&metav1.PatchOptions{},
|
||||
)
|
||||
}
|
||||
|
||||
func TestSliceRemove(t *testing.T) {
|
||||
a := []string{"a", "a", "b", "c"}
|
||||
for i := 0; i < len(a); i++ {
|
||||
if a[i] == "a" {
|
||||
a = append(a[:i], a[i+1:]...)
|
||||
//i--
|
||||
}
|
||||
}
|
||||
fmt.Println(a)
|
||||
}
|
||||
|
||||
98
pkg/route_table_by_net.go
Normal file
98
pkg/route_table_by_net.go
Normal file
@@ -0,0 +1,98 @@
|
||||
//go:build !amd64 && !arm64 && !x86 && !386
|
||||
// +build !amd64,!arm64,!x86,!386
|
||||
|
||||
package pkg
|
||||
|
||||
import (
|
||||
"golang.org/x/net/route"
|
||||
"net"
|
||||
"syscall"
|
||||
)
|
||||
|
||||
// not contains route like 10.61.64/18 10.61.64.1 UCS utun3, todo how about pull a merge to golang sdk???
|
||||
// just contains 10.61.64, which mask is 0, 8, 16, 32, do not middle number
|
||||
func getRouteTableByFetchRIB() (map[string][]*net.IPNet, error) {
|
||||
rib, err := route.FetchRIB(syscall.AF_UNSPEC, syscall.NET_RT_DUMP, 0)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
msgs, err := route.ParseRIB(syscall.NET_RT_DUMP, rib)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
nameToIndex := make(map[int]string)
|
||||
addrs, err := net.Interfaces()
|
||||
for _, addr := range addrs {
|
||||
nameToIndex[addr.Index] = addr.Name
|
||||
}
|
||||
|
||||
m := make(map[string][]route.Addr)
|
||||
for _, msg := range msgs {
|
||||
message := msg.(*route.RouteMessage)
|
||||
if name, found := nameToIndex[message.Index]; found {
|
||||
if v, ok := m[name]; ok {
|
||||
temp := removeNilElement(message)
|
||||
m[name] = append(v, temp...)
|
||||
} else {
|
||||
m[name] = removeNilElement(message)
|
||||
}
|
||||
}
|
||||
}
|
||||
var mm = make(map[string][]*net.IPNet)
|
||||
for k, v := range m {
|
||||
var temp []*net.IPNet
|
||||
for _, addr := range v {
|
||||
if a, ok := addr.(*route.Inet4Addr); ok {
|
||||
var ip = make(net.IP, net.IPv4len)
|
||||
copy(ip, a.IP[:])
|
||||
if one, _ := mask(ip).Size(); one == 0 {
|
||||
continue
|
||||
}
|
||||
temp = append(temp, &net.IPNet{IP: ip, Mask: mask(ip)})
|
||||
} else if a, ok := addr.(*route.Inet6Addr); ok {
|
||||
var ip = make(net.IP, net.IPv6len)
|
||||
copy(ip, a.IP[:])
|
||||
if one, _ := mask(ip).Size(); one == 0 {
|
||||
continue
|
||||
}
|
||||
temp = append(temp, &net.IPNet{IP: ip, Mask: mask(ip)})
|
||||
} else if _, ok := addr.(*route.LinkAddr); ok {
|
||||
//fmt.Println(a)
|
||||
// todo
|
||||
}
|
||||
}
|
||||
mm[k] = temp
|
||||
}
|
||||
return mm, nil
|
||||
}
|
||||
|
||||
func removeNilElement(message *route.RouteMessage) []route.Addr {
|
||||
var temp []route.Addr
|
||||
for _, addr := range message.Addrs {
|
||||
if addr != nil {
|
||||
temp = append(temp, addr)
|
||||
}
|
||||
}
|
||||
return temp
|
||||
}
|
||||
|
||||
// route.FetchRIB fetches a routing information base from the operating system.
|
||||
// In most cases, zero means a wildcard.
|
||||
func mask(ip []byte) net.IPMask {
|
||||
size := 0
|
||||
for i := len(ip) - 1; i >= 0; i-- {
|
||||
if ip[i] == 0 {
|
||||
size++
|
||||
} else {
|
||||
break
|
||||
}
|
||||
}
|
||||
// 0.0.0.0
|
||||
if size == len(ip) {
|
||||
return net.CIDRMask(len(ip)*8, len(ip)*8)
|
||||
}
|
||||
if size == 0 {
|
||||
return net.CIDRMask(0, len(ip)*8)
|
||||
}
|
||||
return net.CIDRMask((len(ip)-size)*8, len(ip)*8)
|
||||
}
|
||||
262
pkg/route_table_darwin.go
Normal file
262
pkg/route_table_darwin.go
Normal file
@@ -0,0 +1,262 @@
|
||||
//go:build darwin
|
||||
// +build darwin
|
||||
|
||||
package pkg
|
||||
|
||||
import (
|
||||
log "github.com/sirupsen/logrus"
|
||||
"net"
|
||||
"os/exec"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// sudo ifconfig utun3 down
|
||||
func disableDevice(conflict []string) error {
|
||||
for _, dev := range conflict {
|
||||
if err := exec.Command("sudo", "ifconfig", dev, "down").Run(); err != nil {
|
||||
log.Errorf("can not disable interface: %s, err: %v", dev, err)
|
||||
return err
|
||||
} else {
|
||||
rollbackFuncList = append(rollbackFuncList, func() {
|
||||
_ = exec.Command("sudo", "ifconfig", dev, "up").Run()
|
||||
})
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func getRouteTable() (map[string][]*net.IPNet, error) {
|
||||
output, err := exec.Command("netstat", "-anr").CombinedOutput()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
split := strings.Split(string(output), "\n")
|
||||
routeTable := make(map[string][]*net.IPNet)
|
||||
for _, i := range split {
|
||||
fields := strings.Fields(i)
|
||||
if len(fields) >= 4 {
|
||||
cidr := fields[0]
|
||||
eth := fields[3]
|
||||
if _, ipNet, err := parseCIDR(cidr); err == nil {
|
||||
if v, ok := routeTable[eth]; ok {
|
||||
routeTable[eth] = append(v, ipNet)
|
||||
} else {
|
||||
routeTable[eth] = []*net.IPNet{ipNet}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return routeTable, nil
|
||||
}
|
||||
|
||||
const big = 0xFFFFFF
|
||||
|
||||
// Decimal to integer.
|
||||
// Returns number, characters consumed, success.
|
||||
func dtoi(s string) (n int, i int, ok bool) {
|
||||
n = 0
|
||||
for i = 0; i < len(s) && '0' <= s[i] && s[i] <= '9'; i++ {
|
||||
n = n*10 + int(s[i]-'0')
|
||||
if n >= big {
|
||||
return big, i, false
|
||||
}
|
||||
}
|
||||
if i == 0 {
|
||||
return 0, 0, false
|
||||
}
|
||||
return n, i, true
|
||||
}
|
||||
|
||||
// Hexadecimal to integer.
|
||||
// Returns number, characters consumed, success.
|
||||
func xtoi(s string) (n int, i int, ok bool) {
|
||||
n = 0
|
||||
for i = 0; i < len(s); i++ {
|
||||
if '0' <= s[i] && s[i] <= '9' {
|
||||
n *= 16
|
||||
n += int(s[i] - '0')
|
||||
} else if 'a' <= s[i] && s[i] <= 'f' {
|
||||
n *= 16
|
||||
n += int(s[i]-'a') + 10
|
||||
} else if 'A' <= s[i] && s[i] <= 'F' {
|
||||
n *= 16
|
||||
n += int(s[i]-'A') + 10
|
||||
} else {
|
||||
break
|
||||
}
|
||||
if n >= big {
|
||||
return 0, i, false
|
||||
}
|
||||
}
|
||||
if i == 0 {
|
||||
return 0, i, false
|
||||
}
|
||||
return n, i, true
|
||||
}
|
||||
|
||||
func parseCIDR(s string) (net.IP, *net.IPNet, error) {
|
||||
indexByte6 := strings.Count(s, ":")
|
||||
indexByte4 := strings.Count(s, ".")
|
||||
if indexByte4 < 0 && indexByte6 < 0 {
|
||||
return nil, nil, &net.ParseError{Type: "CIDR address", Text: s}
|
||||
}
|
||||
|
||||
i := strings.IndexByte(s, '/')
|
||||
var addr, mask string
|
||||
if i < 0 {
|
||||
addr = s
|
||||
// ipv6
|
||||
if indexByte6 > 0 {
|
||||
mask = strconv.Itoa((indexByte6 + 1) * 8)
|
||||
} else {
|
||||
mask = strconv.Itoa((indexByte4 + 1) * 8)
|
||||
}
|
||||
} else {
|
||||
addr, mask = s[:i], s[i+1:]
|
||||
}
|
||||
iplen := net.IPv4len
|
||||
ip := parseIPv4(addr)
|
||||
if ip == nil {
|
||||
iplen = net.IPv6len
|
||||
ip = parseIPv6(addr)
|
||||
}
|
||||
n, i, ok := dtoi(mask)
|
||||
if ip == nil || !ok || i != len(mask) || n < 0 || n > 8*iplen {
|
||||
return nil, nil, &net.ParseError{Type: "CIDR address", Text: s}
|
||||
}
|
||||
m := net.CIDRMask(n, 8*iplen)
|
||||
return ip, &net.IPNet{IP: ip.Mask(m), Mask: m}, nil
|
||||
}
|
||||
|
||||
// Parse IPv4 address (d.d.d.d).
|
||||
func parseIPv4(s string) net.IP {
|
||||
var p [net.IPv4len]byte
|
||||
for i := 0; i < net.IPv4len; i++ {
|
||||
if len(s) == 0 {
|
||||
// Missing octets.
|
||||
continue
|
||||
}
|
||||
if i > 0 {
|
||||
if s[0] != '.' {
|
||||
return nil
|
||||
}
|
||||
s = s[1:]
|
||||
}
|
||||
n, c, ok := dtoi(s)
|
||||
if !ok || n > 0xFF {
|
||||
return nil
|
||||
}
|
||||
if c > 1 && s[0] == '0' {
|
||||
// Reject non-zero components with leading zeroes.
|
||||
return nil
|
||||
}
|
||||
s = s[c:]
|
||||
p[i] = byte(n)
|
||||
}
|
||||
if len(s) != 0 {
|
||||
return nil
|
||||
}
|
||||
return net.IPv4(p[0], p[1], p[2], p[3])
|
||||
}
|
||||
|
||||
func parseIPv6(s string) (ip net.IP) {
|
||||
ip = make(net.IP, net.IPv6len)
|
||||
ellipsis := -1 // position of ellipsis in ip
|
||||
|
||||
// Might have leading ellipsis
|
||||
if len(s) >= 2 && s[0] == ':' && s[1] == ':' {
|
||||
ellipsis = 0
|
||||
s = s[2:]
|
||||
// Might be only ellipsis
|
||||
if len(s) == 0 {
|
||||
return ip
|
||||
}
|
||||
}
|
||||
|
||||
// Loop, parsing hex numbers followed by colon.
|
||||
i := 0
|
||||
for i < net.IPv6len {
|
||||
// Hex number.
|
||||
n, c, ok := xtoi(s)
|
||||
if !ok || n > 0xFFFF {
|
||||
i++
|
||||
continue
|
||||
}
|
||||
|
||||
// If followed by dot, might be in trailing IPv4.
|
||||
if c < len(s) && s[c] == '.' {
|
||||
if ellipsis < 0 && i != net.IPv6len-net.IPv4len {
|
||||
// Not the right place.
|
||||
return nil
|
||||
}
|
||||
if i+net.IPv4len > net.IPv6len {
|
||||
// Not enough room.
|
||||
return nil
|
||||
}
|
||||
ip4 := parseIPv4(s)
|
||||
if ip4 == nil {
|
||||
return nil
|
||||
}
|
||||
ip[i] = ip4[12]
|
||||
ip[i+1] = ip4[13]
|
||||
ip[i+2] = ip4[14]
|
||||
ip[i+3] = ip4[15]
|
||||
s = ""
|
||||
i += net.IPv4len
|
||||
break
|
||||
}
|
||||
|
||||
// Save this 16-bit chunk.
|
||||
ip[i] = byte(n >> 8)
|
||||
ip[i+1] = byte(n)
|
||||
i += 2
|
||||
|
||||
// Stop at end of string.
|
||||
s = s[c:]
|
||||
if len(s) == 0 {
|
||||
break
|
||||
}
|
||||
|
||||
// Otherwise must be followed by colon and more.
|
||||
if s[0] != ':' || len(s) == 1 {
|
||||
return nil
|
||||
}
|
||||
s = s[1:]
|
||||
|
||||
// Look for ellipsis.
|
||||
if s[0] == ':' {
|
||||
if ellipsis >= 0 { // already have one
|
||||
return nil
|
||||
}
|
||||
ellipsis = i
|
||||
s = s[1:]
|
||||
if len(s) == 0 { // can be at end
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Must have used entire string.
|
||||
if len(s) != 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
// If didn't parse enough, expand ellipsis.
|
||||
if i < net.IPv6len {
|
||||
if ellipsis < 0 {
|
||||
return nil
|
||||
}
|
||||
n := net.IPv6len - i
|
||||
for j := i - 1; j >= ellipsis; j-- {
|
||||
ip[j+n] = ip[j]
|
||||
}
|
||||
for j := ellipsis + n - 1; j >= ellipsis; j-- {
|
||||
ip[j] = 0
|
||||
}
|
||||
} else if ellipsis >= 0 {
|
||||
// Ellipsis must represent at least one 0 group.
|
||||
return nil
|
||||
}
|
||||
return ip
|
||||
}
|
||||
48
pkg/route_table_linux.go
Normal file
48
pkg/route_table_linux.go
Normal file
@@ -0,0 +1,48 @@
|
||||
//go:build !windows && !darwin
|
||||
// +build !windows,!darwin
|
||||
|
||||
package pkg
|
||||
|
||||
import (
|
||||
"net"
|
||||
"os/exec"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func getRouteTable() (map[string][]*net.IPNet, error) {
|
||||
output, err := exec.Command("route", "-n").CombinedOutput()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
split := strings.Split(string(output), "\n")
|
||||
routeTable := make(map[string][]*net.IPNet)
|
||||
for _, i := range split {
|
||||
fields := strings.Fields(i)
|
||||
if len(fields) >= 8 {
|
||||
dst := net.ParseIP(fields[0])
|
||||
mask := make(net.IPMask, net.IPv4len)
|
||||
copy(mask, net.ParseIP(fields[2]))
|
||||
eth := fields[7]
|
||||
if v, ok := routeTable[eth]; ok {
|
||||
routeTable[eth] = append(v, &net.IPNet{IP: dst, Mask: mask})
|
||||
} else {
|
||||
routeTable[eth] = []*net.IPNet{{IP: dst, Mask: mask}}
|
||||
}
|
||||
}
|
||||
}
|
||||
return routeTable, nil
|
||||
}
|
||||
|
||||
func disableDevice(list []string) error {
|
||||
for _, dev := range list {
|
||||
if err := exec.Command("sudo", "ifconfig", dev, "down").Run(); err != nil {
|
||||
return err
|
||||
} else {
|
||||
rollbackFuncList = append(rollbackFuncList, func() {
|
||||
_ = exec.Command("sudo", "ifconfig", dev, "up").Run()
|
||||
})
|
||||
}
|
||||
|
||||
}
|
||||
return nil
|
||||
}
|
||||
16
pkg/route_table_windows.go
Normal file
16
pkg/route_table_windows.go
Normal file
@@ -0,0 +1,16 @@
|
||||
//go:build windows
|
||||
// +build windows
|
||||
|
||||
package pkg
|
||||
|
||||
import (
|
||||
"net"
|
||||
)
|
||||
|
||||
func getRouteTable() (map[string][]*net.IPNet, error) {
|
||||
return make(map[string][]*net.IPNet), nil
|
||||
}
|
||||
|
||||
func disableDevice(list []string) error {
|
||||
return nil
|
||||
}
|
||||
@@ -8,10 +8,12 @@ import (
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/fields"
|
||||
"k8s.io/apimachinery/pkg/util/wait"
|
||||
"k8s.io/cli-runtime/pkg/genericclioptions"
|
||||
"k8s.io/client-go/kubernetes"
|
||||
"k8s.io/client-go/rest"
|
||||
"k8s.io/client-go/tools/clientcmd"
|
||||
"k8s.io/client-go/util/retry"
|
||||
cmdutil "k8s.io/kubectl/pkg/cmd/util"
|
||||
"net"
|
||||
"net/http"
|
||||
@@ -33,6 +35,7 @@ var (
|
||||
)
|
||||
|
||||
func TestFunctions(t *testing.T) {
|
||||
kubevpnConnect()
|
||||
t.Cleanup(cancelFunc)
|
||||
t.Parallel()
|
||||
t.Run(runtime.FuncForPC(reflect.ValueOf(pingPodIP).Pointer()).Name(), pingPodIP)
|
||||
@@ -182,10 +185,14 @@ func dialUDP(t *testing.T) {
|
||||
if len(ip) == 0 {
|
||||
t.Errorf("can not found pods for service reviews")
|
||||
}
|
||||
time.Sleep(time.Second * 5)
|
||||
log.Infof("dail udp to ip: %s", ip)
|
||||
err = client(ip, port)
|
||||
if err != nil {
|
||||
log.Printf("dail udp to ip: %s", ip)
|
||||
if err = retry.OnError(
|
||||
wait.Backoff{Duration: time.Second, Factor: 2, Jitter: 0.2, Steps: 5},
|
||||
func(err error) bool {
|
||||
return err != nil
|
||||
}, func() error {
|
||||
return client(ip, port)
|
||||
}); err != nil {
|
||||
t.Errorf("can not access pod ip: %s, port: %v", ip, port)
|
||||
}
|
||||
}
|
||||
@@ -201,6 +208,11 @@ func client(ip string, port int) error {
|
||||
}
|
||||
defer udpConn.Close()
|
||||
|
||||
err = udpConn.SetDeadline(time.Now().Add(time.Second * 30))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// 发送数据
|
||||
sendData := []byte("hello server!")
|
||||
_, err = udpConn.Write(sendData)
|
||||
@@ -251,8 +263,7 @@ func server(port int) {
|
||||
}
|
||||
}
|
||||
|
||||
func init() {
|
||||
initClient()
|
||||
func kubevpnConnect() {
|
||||
var ctx context.Context
|
||||
ctx, cancelFunc = context.WithCancel(context.TODO())
|
||||
childCtx, timeoutFunc := context.WithTimeout(ctx, time.Minute*10)
|
||||
@@ -268,7 +279,7 @@ func init() {
|
||||
<-childCtx.Done()
|
||||
}
|
||||
|
||||
func initClient() {
|
||||
func init() {
|
||||
var err error
|
||||
|
||||
configFlags := genericclioptions.NewConfigFlags(true)
|
||||
|
||||
@@ -37,6 +37,7 @@ func Listener(config Config) (net.Listener, error) {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
ln.addr = conn.LocalAddr()
|
||||
|
||||
addrs, _ := ifce.Addrs()
|
||||
|
||||
Reference in New Issue
Block a user