8000 update socket-lookup demo · lx1036/code@951c481 · GitHub
[go: up one dir, main page]

Skip to content

Commit 951c481

Browse files
author
shenming
committed
update socket-lookup demo
1 parent 1f0777f commit 951c481

File tree

8 files changed

+542
-61
lines changed

8 files changed

+542
-61
lines changed
Lines changed: 168 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,168 @@
1+
package main
2+
3+
import (
4+
"errors"
5+
"fmt"
6+
"github.com/cilium/ebpf"
7+
"github.com/sirupsen/logrus"
8+
"github.com/spf13/cobra"
9+
"github.com/spf13/viper"
10+
"inet.af/netaddr"
11+
"strings"
12+
"unsafe"
13+
)
14+
15+
var (
16+
bindLabel string
17+
bindProtocol string
18+
bindIpPrefix string
19+
bindPort int
20+
)
21+
22+
func init() {
23+
rootCmd.AddCommand(bindCmd)
24+
25+
flags := bindCmd.PersistentFlags()
26+
flags.StringVarP(&bindLabel, "label", "", "foo", "label")
27+
viper.BindPFlag("label", flags.Lookup("label"))
28+
flags.StringVarP(&bindProtocol, "protocol", "", "tcp", "protocol")
29+
viper.BindPFlag("protocol", flags.Lookup("protocol"))
30+
flags.StringVarP(&bindIpPrefix, "ip-prefix", "", "127.0.0.0/24", "ip-prefix")
31+
viper.BindPFlag("ip-prefix", flags.Lookup("ip-prefix"))
32+
flags.IntVarP(&bindPort, "port", "", 0, "port")
33+
viper.BindPFlag("port", flags.Lookup("port"))
34+
35+
}
36+
37+
var bindCmd = &cobra.Command{
38+
Use: "bind",
39+
Example: `
40+
bind --label=foo --protocol=udp --ip-prefix=127.0.0.1 --port=0
41+
bind --label=bar --protocol=tcp --ip-prefix=127.0.0.1/32 --port=80
42+
`,
43+
Run: func(cmd *cobra.Command, args []string) {
44+
dispatcher, err := OpenDispatcher()
45+
if err != nil {
46+
logrus.Errorf("[bind]err: %v", err)
47+
return
48+
}
49+
50+
binding, err := NewBinding(bindLabel, ConvertProtocol(bindProtocol), bindIpPrefix, uint16(bindPort))
51+
if err != nil {
52+
logrus.Errorf("[bind]err: %v", err)
53+
return
54+
}
55+
56+
dispatcher.AddBinding(binding)
57+
},
58+
}
59+
60+
type Binding struct {
61+
Label string
62+
Protocol Protocol
63+
Prefix netaddr.IPPrefix
64+
Port uint16
65+
}
66+
67+
func NewBinding(label string, proto Protocol, prefix string, port uint16) (*Binding, error) {
68+
cidr, err := ParsePrefix(prefix)
69+
if err != nil {
70+
return nil, err
71+
}
72+
73+
return &Binding{
74+
label,
75+
proto,
76+
netaddr.IPPrefixFrom(cidr.IP(), cidr.Bits()).Masked(),
77+
port,
78+
}, nil
79+
}
80+
81+
// ParsePrefix 127.0.0.1 or 127.0.0.1/24
82+
func ParsePrefix(prefix string) (netaddr.IPPrefix, error) {
83+
if strings.ContainsRune(prefix, '/') {
84+
return netaddr.ParseIPPrefix(prefix)
85+
}
86+
87+
ip, err := netaddr.ParseIP(prefix)
88+
if err != nil {
89+
return netaddr.IPPrefix{}, err
90+
}
91+
92+
var prefixBits uint8
93+
if ip.Is4() {
94+
prefixBits = 32
95+
} else {
96+
prefixBits = 128
97+
}
98+
99+
return netaddr.IPPrefixFrom(ip, prefixBits), nil
100+
}
101+
102+
type bindingKey struct {
103+
PrefixLen uint32
104+
Protocol Protocol
105+
Port uint16
106+
IP [16]byte
107+
}
108+
109+
const bindingKeyHeaderBits = uint8(unsafe.Sizeof(bindingKey{}.Protocol)+unsafe.Sizeof(bindingKey{}.Port)) * 8
110+
111+
func newBindingKey(bind *Binding) *bindingKey {
112+
// Get the length of the prefix
113+
prefixLen := bind.Prefix.Bits()
114+
115+
// If the prefix is v4, offset it by 96
116+
if bind.Prefix.IP().Is4() { // ???
117+
prefixLen += 96
118+
}
119+
120+
key := bindingKey{
121+
PrefixLen: uint32(bindingKeyHeaderBits + prefixLen), // ???
122+
Protocol: bind.Protocol,
123+
Port: bind.Port,
124+
IP: bind.Prefix.IP().As16(),
125+
}
126+
127+
return &key
128+
}
129+
130+
type bindingValue struct {
131+
ID DestinationID
132+
PrefixLen uint32
133+
}
134+
135+
// AddBinding bindings 和 destinations bpf map 要一一对应
136+
func (dispatcher *Dispatcher) AddBinding(binding *Binding) error {
137+
138+
key := newBindingKey(binding)
139+
140+
var old bindingValue
141+
var releaseOldID bool
142+
if err := dispatcher.bindings.Lookup(key, &old); err == nil {
143+
// Since the LPM trie will return the "best" match we have to make sure
144+
// that the prefix length matches to ensure that we're replacing a binding,
145+
// not just installing a more specific one.
146+
releaseOldID = old.PrefixLen == key.PrefixLen
147+
} else if !errors.Is(err, ebpf.ErrKeyNotExist) {
148+
return fmt.Errorf("lookup binding: %s", err)
149+
}
150+
151+
destination := newDestinationFromBinding(binding)
152+
id, err := dispatcher.destinations.Acquire(destination) // -> destinations map
153+
if err != nil {
154+
return fmt.Errorf("acquire destination: %s", err)
155+
}
156+
157+
value := bindingValue{ID: id, PrefixLen: key.PrefixLen}
158+
err = dispatcher.bindings.Put(key, &value) // -> bindings map
159+
if err != nil {
160+
return err
161+
}
162+
163+
if releaseOldID {
164+
dispatcher.destinations.ReleaseByID(old.ID)
165+
}
166+
167+
return nil
168+
}
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
2+
import socket
3+
import os
4+
5+
# 创建一个TCP/IP socket
6+
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
7+
# 绑定到所有接口的特定端口
8+
server_address = ('127.0.0.1', 10000)
9+
sock.bind(server_address)
10+
# 开始监听连接
11+
sock.listen(1)
12+
13+
# 获取当前进程的PID
14+
current_pid = os.getpid()
15+
print("当前进程的PID:", current_pid)
16+
17+
while True:
18+
# 等待连接
19+
connection, client_address = sock.accept()
20+
print('连接来自', client_address)
21+
22+
# client_address 是一个元组,包含 IP 和端口
23+
client_ip, client_port = client_address
24+
print('客户端IP:', client_ip)
25+
print('客户端端口:', client_port)
26+
27+
# 处理客户端连接...
28+
# 关闭连接
29+
connection.close()
30+
31+
# python3 client-port.py
32+
# tubectl bind foo tcp 127.0.0.1 4322
33+
# tubectl register-pid 485850 foo tcp 127.0.0.1 10000
34+
# echo hello | nc -q 1 127.0.0.1 4322
35+
36+
# 保留源目的端口 4322,而不是 10000,验证通过!!!
37+
# 抓包 4322 有包: tcpdump -i lo port 4322
38+
# 抓包 10000 没有包: tcpdump -i lo port 10000
39+

0 commit comments

Comments
 (0)
0