girl 0.53.0 → 0.54.0
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of girl might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/lib/girl/udp.rb +229 -119
- data/lib/girl/udpd.rb +210 -105
- data/lib/girl/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 19acd0601b223880d31ac0294928830d0a683e419bce6da31712914bebc7b65d
|
4
|
+
data.tar.gz: 8b112d1eec1f6a83851e8b12e546217c8aeb59f9c743e56d600a23c2f5fc333e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d9bc77923d0a6e1637cd3b29c2f15aca7d882bf7b6b7501c51cf0fac529244e63e2ce4f8ca47594886d598479eaf3f545801a9f5fdb5fd00075a520cd69db86f
|
7
|
+
data.tar.gz: e57bdec56fb691207a9f4c1d47622c0f64ef9d4d3b703afba745281e41c50ae84825809af59fc84b1740eceb525a063b8ed3be130295af3725751518c9c44b3e
|
data/lib/girl/udp.rb
CHANGED
@@ -5,7 +5,7 @@ require 'socket'
|
|
5
5
|
# Girl::Udp - 转发udp。近端。
|
6
6
|
#
|
7
7
|
# usage
|
8
|
-
#
|
8
|
+
# ======
|
9
9
|
#
|
10
10
|
# Girl::Udpd.new( 3030 ).looping # 远端
|
11
11
|
#
|
@@ -13,6 +13,43 @@ require 'socket'
|
|
13
13
|
#
|
14
14
|
# iptables -t nat -A PREROUTING -p udp -d game.server.ip -j REDIRECT --to-ports 1313
|
15
15
|
#
|
16
|
+
# control message
|
17
|
+
# ================
|
18
|
+
#
|
19
|
+
# C: 1 (tun > udpd: req a tund) -> orig_src_addr -> dest_addr
|
20
|
+
# C: 2 (udpd > tun: tund port) -> n: tund_port -> tun_addr
|
21
|
+
# C: 3 (udpd > tun: req a chain tun) -> new_dest_addr -> root_dest_addr
|
22
|
+
# C: 4 (tun > udpd: req a chain tund) -> orig_src_addr -> dest_addr -> root_dest_addr
|
23
|
+
# C: 5 (tun > tund: hello)
|
24
|
+
#
|
25
|
+
# flow
|
26
|
+
# =====
|
27
|
+
#
|
28
|
+
# src从本机端口发出,发往两个目的地:
|
29
|
+
#
|
30
|
+
# src1=redir.recv -> new tun1 -> ctlmsg.1 -> udpd.recv -> new tund1 -> tund1.recv -> dst1
|
31
|
+
# src2=redir.recv -> new tun2 -> ctlmsg.1 -> udpd.recv -> new tund2 -> tund2.recv -> dst2
|
32
|
+
#
|
33
|
+
# src发往dst2,iptables会映射一个新的端口src2用来代理dst2的返程。可以在nf_conntrack里找到转换前的原端口,看到src2和src1是一样的。
|
34
|
+
#
|
35
|
+
# p2p对面先到:
|
36
|
+
#
|
37
|
+
# dst3=tund1.recv -> ctlmsg.3 -> tun1.recv -> new tun3 -> ctlmsg.4 -> udpd.recv -> new tund3 -> tun3.recv -> tun3.dest_rbuffs
|
38
|
+
# -> src3=redir.recv -> tun3=tuns.find([:orig_src dst3]) -> redir.wbuffs.append(tun3.dest_rbuffs) -> redir.send_to(src3)
|
39
|
+
#
|
40
|
+
# p2p对面先到的情况,准备好tun3-tund3,一边redir接到src3,根据[转换前地址 目的地],匹中tun3。
|
41
|
+
#
|
42
|
+
# 来自对面的数据,先存在tund1身上,再移给tun3,src3匹中tun3后,移给redir写入src3。
|
43
|
+
#
|
44
|
+
# p2p自己先出去:
|
45
|
+
#
|
46
|
+
# src2=redir.recv -> new tun2 -> ctlmsg.1 -> udpd.recv -> new tund2 -> tund2.recv -> tund2.send_to(dst2) -> 撞死
|
47
|
+
# -> dst2=tund1.recv -> tund2=tunds.find(tun1_ip-orig_src-dst2) -> tun2.recv -> redir.send_to(src2)
|
48
|
+
#
|
49
|
+
# p2p自己先出去的情况,包会撞死,并且这时还不知道tun2-tund2转发的是p2p流量。不用知道,先把发出的包缓存一下(存最后一个就行,一般是连发打洞的数据)。
|
50
|
+
#
|
51
|
+
# 一边tund1接到dst2,根据[:tun_ip :orig_src dst2],匹中tund2。这时知道了tund2是p2p,由tund1代之和dst2通信(先把缓存的最后一个包发过去)。
|
52
|
+
#
|
16
53
|
module Girl
|
17
54
|
class Udp
|
18
55
|
|
@@ -24,31 +61,30 @@ module Girl
|
|
24
61
|
redir.bind( Socket.sockaddr_in( redir_port, '0.0.0.0' ) )
|
25
62
|
puts "redir bound on #{ redir_port } #{ Time.new }"
|
26
63
|
|
27
|
-
udp = Socket.new( Socket::AF_INET, Socket::SOCK_DGRAM, 0 )
|
28
|
-
udp.setsockopt( Socket::SOL_SOCKET, Socket::SO_REUSEPORT, 1 )
|
29
|
-
udp.bind( Socket.sockaddr_in( 0, '0.0.0.0' ) )
|
30
|
-
puts "udp bound on #{ udp.local_address.ip_unpack.last } #{ Time.new }"
|
31
|
-
|
32
64
|
@mutex = Mutex.new
|
65
|
+
@udpd_host = udpd_host
|
33
66
|
@udpd_addr = Socket.sockaddr_in( udpd_port, udpd_host )
|
34
67
|
@ctlw = ctlw
|
35
68
|
@redir = redir
|
36
|
-
@
|
37
|
-
@reads = [ ctlr, redir, udp ]
|
69
|
+
@reads = [ ctlr, redir ]
|
38
70
|
@writes = []
|
39
71
|
@closings = []
|
40
72
|
@roles = {
|
41
|
-
ctlr => :ctlr,
|
42
|
-
redir => :redir
|
43
|
-
udp => :udp
|
73
|
+
ctlr => :ctlr, # :ctlr / :redir / :tun
|
74
|
+
redir => :redir
|
44
75
|
}
|
45
|
-
@
|
46
|
-
@
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
76
|
+
@redir_wbuffs = [] # [ src_addr data ] ...
|
77
|
+
@tuns = {} # [ orig_src_addr dest_addr ] => tun
|
78
|
+
@tun_infos = {} # tun => {}
|
79
|
+
# orig_src_addr: sockaddr
|
80
|
+
# dest_addr: sockaddr
|
81
|
+
# src_addr: sockaddr
|
82
|
+
# tun_addr: sockaddr
|
83
|
+
# tund_addr: sockaddr
|
84
|
+
# ctlmsgs: []
|
85
|
+
# wbuffs: []
|
86
|
+
# dest_rbuffs: []
|
87
|
+
# last_traff_at: now
|
52
88
|
end
|
53
89
|
|
54
90
|
def looping
|
@@ -64,15 +100,18 @@ module Girl
|
|
64
100
|
read_ctlr( sock )
|
65
101
|
when :redir
|
66
102
|
read_redir( sock )
|
67
|
-
when :
|
68
|
-
|
69
|
-
when :src
|
70
|
-
read_src( sock )
|
103
|
+
when :tun
|
104
|
+
read_tun( sock )
|
71
105
|
end
|
72
106
|
end
|
73
107
|
|
74
108
|
ws.each do | sock |
|
75
|
-
|
109
|
+
case @roles[ sock ]
|
110
|
+
when :redir
|
111
|
+
write_redir( sock )
|
112
|
+
when :tun
|
113
|
+
write_tun( sock )
|
114
|
+
end
|
76
115
|
end
|
77
116
|
end
|
78
117
|
end
|
@@ -85,144 +124,215 @@ module Girl
|
|
85
124
|
private
|
86
125
|
|
87
126
|
def read_ctlr( ctlr )
|
88
|
-
|
89
|
-
|
127
|
+
od_addr = ctlr.read( 32 )
|
128
|
+
tun = @tuns[ od_addr ]
|
90
129
|
|
91
|
-
if
|
92
|
-
add_closing(
|
130
|
+
if tun
|
131
|
+
add_closing( tun )
|
93
132
|
end
|
94
133
|
end
|
95
134
|
|
96
135
|
def read_redir( redir )
|
97
136
|
data, addrinfo, rflags, *controls = redir.recvmsg
|
98
|
-
|
99
137
|
src_addr = addrinfo.to_sockaddr
|
100
|
-
|
101
|
-
|
138
|
+
|
139
|
+
# puts "debug redir recv #{ data.inspect } from #{ addrinfo.inspect }"
|
140
|
+
# 2 udp 5 src 7 sport 9 [UNREPLIED] 11 dst 13 dport
|
141
|
+
# 2 udp 5 src 7 sport 10 dst 12 dport
|
142
|
+
bin = IO.binread( '/proc/net/nf_conntrack' )
|
143
|
+
rows = bin.split( "\n" ).map { | line | line.split( ' ' ) }
|
144
|
+
row = rows.find { | _row | _row[ 2 ] == 'udp' && ( ( _row[ 9 ] == '[UNREPLIED]' && _row[ 11 ].split( '=' )[ 1 ] == addrinfo.ip_address && _row[ 13 ].split( '=' )[ 1 ].to_i == addrinfo.ip_port ) || ( _row[ 10 ].split( '=' )[ 1 ] == addrinfo.ip_address && _row[ 12 ].split( '=' )[ 1 ].to_i == addrinfo.ip_port ) ) }
|
102
145
|
|
103
146
|
unless row
|
104
|
-
puts "miss #{ addrinfo.inspect } #{ Time.new }"
|
147
|
+
puts "miss conntrack #{ addrinfo.inspect } #{ Time.new }"
|
148
|
+
IO.binwrite( '/tmp/nf_conntrack', bin )
|
105
149
|
return
|
106
150
|
end
|
107
151
|
|
108
|
-
|
109
|
-
|
152
|
+
orig_src_ip = row[ 5 ].split( '=' )[ 1 ]
|
153
|
+
orig_src_port = row[ 7 ].split( '=' )[ 1 ].to_i
|
154
|
+
dest_ip = row[ 6 ].split( '=' )[ 1 ]
|
155
|
+
dest_port = row[ 8 ].split( '=' )[ 1 ].to_i
|
156
|
+
orig_src_addr = Socket.sockaddr_in( orig_src_port, orig_src_ip )
|
157
|
+
dest_addr = Socket.sockaddr_in( dest_port, dest_ip )
|
158
|
+
tun = @tuns[ [ orig_src_addr, dest_addr ].join ]
|
159
|
+
|
160
|
+
if tun
|
161
|
+
tun_info = @tun_infos[ tun ]
|
162
|
+
|
163
|
+
unless tun_info[ :src_addr ]
|
164
|
+
# p2p paired
|
165
|
+
tun_info[ :src_addr ] = src_addr
|
166
|
+
|
167
|
+
if tun_info[ :dest_rbuffs ].any?
|
168
|
+
# puts "debug move dest_rbuff to redir #{ Addrinfo.new( tun_info[ :dest_addr ] ).inspect } #{ Addrinfo.new( tun_info[ :orig_src_addr ] ).inspect }"
|
169
|
+
@redir_wbuffs += tun_info[ :dest_rbuffs ].map{ | buff | [ src_addr, buff ] }
|
170
|
+
tun_info[ :dest_rbuffs ].clear
|
171
|
+
add_redir_write( redir )
|
172
|
+
end
|
173
|
+
end
|
174
|
+
else
|
175
|
+
tun = new_a_tun( orig_src_addr, dest_addr, src_addr )
|
176
|
+
tun_info = @tun_infos[ tun ]
|
177
|
+
|
178
|
+
# puts "debug send C: 1 (tun > udpd: req a tund) -> orig_src_addr dest_addr #{ Addrinfo.new( orig_src_addr ).inspect } #{ Addrinfo.new( dest_addr ).inspect }"
|
179
|
+
ctlmsg = [ [ 1 ].pack( 'C' ), orig_src_addr, dest_addr ].join
|
180
|
+
add_ctlmsg( tun, ctlmsg )
|
181
|
+
end
|
182
|
+
|
183
|
+
add_write( tun, data )
|
110
184
|
end
|
111
185
|
|
112
|
-
def
|
113
|
-
data, addrinfo, rflags, *controls =
|
114
|
-
|
186
|
+
def read_tun( tun )
|
187
|
+
data, addrinfo, rflags, *controls = tun.recvmsg
|
188
|
+
from_addr = addrinfo.to_sockaddr
|
189
|
+
tun_info = @tun_infos[ tun ]
|
190
|
+
tun_info[ :last_traff_at ] = Time.new
|
115
191
|
|
116
|
-
if
|
117
|
-
|
118
|
-
return
|
119
|
-
end
|
192
|
+
if from_addr == @udpd_addr
|
193
|
+
ctl_num = data[ 0 ].unpack( 'C' ).first
|
120
194
|
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
@half = nil
|
125
|
-
else
|
126
|
-
dest_addr = data[ 0, 16 ]
|
127
|
-
src_addr = data[ 16, 16 ]
|
128
|
-
data = data[ 32..-1 ]
|
129
|
-
end
|
195
|
+
case ctl_num
|
196
|
+
when 2 # C: 2 (udpd > tun: tund port) -> n: tund_port -> tun_addr
|
197
|
+
return if tun_info[ :tund_addr ]
|
130
198
|
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
src.setsockopt( Socket::SOL_SOCKET, Socket::SO_REUSEPORT, 1 )
|
137
|
-
src.bind( Socket.sockaddr_in( 0, '0.0.0.0' ) )
|
138
|
-
|
139
|
-
@srcs[ sd_addr ] = src
|
140
|
-
@src_infos[ src ] = {
|
141
|
-
sd_addr: sd_addr,
|
142
|
-
src_addr: src_addr,
|
143
|
-
dest_addr: dest_addr,
|
144
|
-
wbuffs: [],
|
145
|
-
last_traff_at: Time.new
|
146
|
-
}
|
147
|
-
|
148
|
-
@roles[ src ] = :src
|
149
|
-
@reads << src
|
150
|
-
end
|
199
|
+
tund_port = data[ 1, 2 ].unpack( 'n' ).first
|
200
|
+
tun_addr = data[ 3, 16 ]
|
201
|
+
tund_addr = Socket.sockaddr_in( tund_port, @udpd_host )
|
202
|
+
tun_info[ :tun_addr ] = tun_addr
|
203
|
+
tun_info[ :tund_addr ] = tund_addr
|
151
204
|
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
205
|
+
# flush wbuffs to tund, if empty, just send a cross nat msg (5: hello), tund should ignore hello
|
206
|
+
if tun_info[ :wbuffs ].empty?
|
207
|
+
tun_info[ :wbuffs ] << [ 5 ].pack( 'C' )
|
208
|
+
end
|
156
209
|
|
157
|
-
|
158
|
-
|
210
|
+
add_write( tun )
|
211
|
+
when 3 # C: 3 (udpd > tun: req a chain tun) -> new_dest_addr -> root_dest_addr
|
212
|
+
new_dest_addr = data[ 1, 16 ]
|
213
|
+
root_dest_addr = data[ 17, 16 ]
|
214
|
+
orig_src_addr = tun_info[ :orig_src_addr ]
|
215
|
+
chain_tun = @tuns[ [ orig_src_addr, new_dest_addr ].join ]
|
159
216
|
|
160
|
-
|
161
|
-
|
217
|
+
unless chain_tun
|
218
|
+
chain_tun = new_a_tun( orig_src_addr, new_dest_addr )
|
219
|
+
end
|
162
220
|
|
163
|
-
|
164
|
-
|
165
|
-
|
221
|
+
# puts "debug send C: 4 (tun > udpd: req a chain tund) -> orig_src_addr -> dest_addr -> root_dest_addr #{ Addrinfo.new( orig_src_addr ).inspect } #{ Addrinfo.new( new_dest_addr ).inspect } #{ Addrinfo.new( root_dest_addr ).inspect }"
|
222
|
+
ctlmsg = [ [ 4 ].pack( 'C' ), orig_src_addr, new_dest_addr, root_dest_addr ].join
|
223
|
+
add_ctlmsg( chain_tun, ctlmsg )
|
224
|
+
end
|
225
|
+
elsif from_addr == tun_info[ :tund_addr ]
|
226
|
+
if tun_info[ :src_addr ]
|
227
|
+
@redir_wbuffs << [ tun_info[ :src_addr ], data ]
|
228
|
+
add_redir_write( @redir )
|
229
|
+
else
|
230
|
+
# puts "debug save to tun.dest_rbuffs #{ data.inspect }"
|
231
|
+
tun_info[ :dest_rbuffs ] << data
|
232
|
+
end
|
233
|
+
end
|
234
|
+
end
|
235
|
+
|
236
|
+
def write_redir( redir )
|
237
|
+
if @redir_wbuffs.empty?
|
238
|
+
@writes.delete( redir )
|
239
|
+
return
|
240
|
+
end
|
241
|
+
|
242
|
+
src_addr, data = @redir_wbuffs.shift
|
243
|
+
redir.sendmsg( data, 0, src_addr )
|
166
244
|
end
|
167
245
|
|
168
|
-
def
|
169
|
-
if @closings.include?(
|
170
|
-
|
246
|
+
def write_tun( tun )
|
247
|
+
if @closings.include?( tun )
|
248
|
+
close_tun( tun )
|
171
249
|
return
|
172
250
|
end
|
173
251
|
|
174
|
-
|
175
|
-
|
252
|
+
tun_info = @tun_infos[ tun ]
|
253
|
+
ctlmsg = tun_info[ :ctlmsgs ].shift
|
176
254
|
|
177
|
-
|
178
|
-
|
255
|
+
if ctlmsg
|
256
|
+
tun.sendmsg( ctlmsg, 0, @udpd_addr )
|
179
257
|
return
|
180
258
|
end
|
181
259
|
|
182
|
-
|
183
|
-
|
184
|
-
rescue Errno::EACCES, Errno::EINTR => e
|
185
|
-
puts "src sendmsg #{ e.class } #{ Time.new }"
|
186
|
-
add_closing( src )
|
260
|
+
if tun_info[ :tund_addr ].nil? || tun_info[ :wbuffs ].empty?
|
261
|
+
@writes.delete( tun )
|
187
262
|
return
|
188
263
|
end
|
189
264
|
|
190
|
-
|
265
|
+
data = tun_info[ :wbuffs ].shift
|
266
|
+
tun.sendmsg( data, 0, tun_info[ :tund_addr ] )
|
191
267
|
end
|
192
268
|
|
193
|
-
def
|
194
|
-
|
195
|
-
|
269
|
+
def add_ctlmsg( tun, ctlmsg )
|
270
|
+
tun_info = @tun_infos[ tun ]
|
271
|
+
tun_info[ :ctlmsgs ] << ctlmsg
|
272
|
+
|
273
|
+
unless @writes.include?( tun )
|
274
|
+
@writes << tun
|
196
275
|
end
|
197
276
|
end
|
198
277
|
|
199
|
-
def
|
200
|
-
|
201
|
-
|
278
|
+
def add_write( tun, data = nil )
|
279
|
+
tun_info = @tun_infos[ tun ]
|
280
|
+
|
281
|
+
if data
|
282
|
+
tun_info[ :wbuffs ] << data
|
202
283
|
end
|
203
284
|
|
204
|
-
|
285
|
+
unless @writes.include?( tun )
|
286
|
+
@writes << tun
|
287
|
+
end
|
205
288
|
end
|
206
289
|
|
207
|
-
def
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
@closings.delete( src )
|
212
|
-
@roles.delete( src )
|
213
|
-
src_info = @src_infos.delete( src )
|
214
|
-
@srcs.delete( src_info[ :sd_addr ] )
|
290
|
+
def add_redir_write( redir )
|
291
|
+
unless @writes.include?( redir )
|
292
|
+
@writes << redir
|
293
|
+
end
|
215
294
|
end
|
216
295
|
|
217
|
-
def
|
218
|
-
|
219
|
-
@
|
220
|
-
rescue Errno::EMSGSIZE => e
|
221
|
-
puts "#{ e.class } #{ Time.new }"
|
222
|
-
[ data[ 0, 32 ], data[ 32..-1 ] ].each do | part |
|
223
|
-
@udp.sendmsg( part, 0, @udpd_addr )
|
224
|
-
end
|
296
|
+
def add_closing( tun )
|
297
|
+
unless @closings.include?( tun )
|
298
|
+
@closings << tun
|
225
299
|
end
|
300
|
+
|
301
|
+
add_write( tun )
|
302
|
+
end
|
303
|
+
|
304
|
+
def close_tun( tun )
|
305
|
+
tun.close
|
306
|
+
@reads.delete( tun )
|
307
|
+
@writes.delete( tun )
|
308
|
+
@closings.delete( tun )
|
309
|
+
@roles.delete( tun )
|
310
|
+
tun_info = @tun_infos.delete( tun )
|
311
|
+
@tuns.delete( [ tun_info[ :orig_src_addr ], tun_info[ :dest_addr ] ].join )
|
312
|
+
end
|
313
|
+
|
314
|
+
def new_a_tun( orig_src_addr, dest_addr, src_addr = nil )
|
315
|
+
tun = Socket.new( Socket::AF_INET, Socket::SOCK_DGRAM, 0 )
|
316
|
+
tun.setsockopt( Socket::SOL_SOCKET, Socket::SO_REUSEPORT, 1 )
|
317
|
+
tun.bind( Socket.sockaddr_in( 0, '0.0.0.0' ) )
|
318
|
+
|
319
|
+
@tuns[ [ orig_src_addr, dest_addr ].join ] = tun
|
320
|
+
@tun_infos[ tun ] = {
|
321
|
+
orig_src_addr: orig_src_addr,
|
322
|
+
dest_addr: dest_addr,
|
323
|
+
src_addr: src_addr,
|
324
|
+
tun_addr: nil,
|
325
|
+
tund_addr: nil,
|
326
|
+
ctlmsgs: [],
|
327
|
+
wbuffs: [],
|
328
|
+
dest_rbuffs: [],
|
329
|
+
last_traff_at: Time.new
|
330
|
+
}
|
331
|
+
|
332
|
+
@roles[ tun ] = :tun
|
333
|
+
@reads << tun
|
334
|
+
|
335
|
+
tun
|
226
336
|
end
|
227
337
|
|
228
338
|
def loop_expire
|
@@ -233,9 +343,9 @@ module Girl
|
|
233
343
|
@mutex.synchronize do
|
234
344
|
now = Time.new
|
235
345
|
|
236
|
-
@
|
237
|
-
if now -
|
238
|
-
@ctlw.write(
|
346
|
+
@tun_infos.values.each do | tun_info |
|
347
|
+
if now - tun_info[ :last_traff_at ] > 1800
|
348
|
+
@ctlw.write( [ tun_info[ :orig_src_addr ], tun_info[ :dest_addr ] ].join )
|
239
349
|
end
|
240
350
|
end
|
241
351
|
end
|
data/lib/girl/udpd.rb
CHANGED
@@ -22,16 +22,25 @@ module Girl
|
|
22
22
|
@writes = []
|
23
23
|
@closings = []
|
24
24
|
@roles = {
|
25
|
-
ctlr => :ctlr,
|
25
|
+
ctlr => :ctlr, # :ctlr / :udpd / :tund
|
26
26
|
udpd => :udpd
|
27
27
|
}
|
28
|
-
@
|
29
|
-
@
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
28
|
+
@udpd_wbuffs = [] # [ tun_addr ctlmsg ] ...
|
29
|
+
@tunds = {} # [ tun_ip_addr orig_src_addr dest_addr ] => tund
|
30
|
+
@tund_infos = {} # tund => {}
|
31
|
+
# port: port
|
32
|
+
# is_tunneled: false
|
33
|
+
# tun_addr: sockaddr
|
34
|
+
# tun_ip_addr: sockaddr
|
35
|
+
# orig_src_addr: sockaddr
|
36
|
+
# dest_addr: sockaddr
|
37
|
+
# root_tund: tund1
|
38
|
+
# wbuffs: []
|
39
|
+
# is_dest_responsed: false
|
40
|
+
# dest_wmemos: []
|
41
|
+
# new_dest_rbuffs: { new_dest_addr => [] }
|
42
|
+
# last_traff_at: now
|
43
|
+
@od_addr_rbuffs = {}
|
35
44
|
end
|
36
45
|
|
37
46
|
def looping
|
@@ -47,13 +56,18 @@ module Girl
|
|
47
56
|
read_ctlr( sock )
|
48
57
|
when :udpd
|
49
58
|
read_udpd( sock )
|
50
|
-
when :
|
51
|
-
|
59
|
+
when :tund
|
60
|
+
read_tund( sock )
|
52
61
|
end
|
53
62
|
end
|
54
63
|
|
55
64
|
ws.each do | sock |
|
56
|
-
|
65
|
+
case @roles[ sock ]
|
66
|
+
when :udpd
|
67
|
+
write_udpd( sock )
|
68
|
+
when :tund
|
69
|
+
write_tund( sock )
|
70
|
+
end
|
57
71
|
end
|
58
72
|
end
|
59
73
|
end
|
@@ -66,138 +80,229 @@ module Girl
|
|
66
80
|
private
|
67
81
|
|
68
82
|
def read_ctlr( ctlr )
|
69
|
-
|
70
|
-
|
83
|
+
tod_addr = ctlr.read( 48 )
|
84
|
+
tund = @tunds[ tod_addr ]
|
71
85
|
|
72
|
-
if
|
73
|
-
|
74
|
-
add_closing( dest )
|
86
|
+
if tund
|
87
|
+
add_closing( tund )
|
75
88
|
end
|
76
89
|
end
|
77
90
|
|
78
91
|
def read_udpd( udpd )
|
92
|
+
# C: 1 (tun > udpd: req a tund) -> orig_src_addr -> dest_addr
|
93
|
+
# C: 4 (tun > udpd: req a chain tund) -> orig_src_addr -> dest_addr -> root_dest_addr
|
79
94
|
data, addrinfo, rflags, *controls = udpd.recvmsg
|
80
|
-
|
95
|
+
# puts "debug udpd recv #{ data.inspect } from #{ addrinfo.inspect }"
|
96
|
+
ctl_num = data[ 0 ].unpack( 'C' ).first
|
97
|
+
orig_src_addr = data[ 1, 16 ]
|
98
|
+
dest_addr = data[ 17, 16 ]
|
99
|
+
tun_addr = addrinfo.to_sockaddr
|
100
|
+
tun_ip_addr = Addrinfo.ip( addrinfo.ip_address ).to_sockaddr
|
101
|
+
|
102
|
+
return unless [ 1, 4 ].include?( ctl_num )
|
103
|
+
return unless Addrinfo.new( orig_src_addr ).ipv4?
|
104
|
+
return unless Addrinfo.new( dest_addr ).ipv4?
|
81
105
|
|
82
|
-
|
106
|
+
tund = @tunds[ [ tun_ip_addr, orig_src_addr, dest_addr ].join ]
|
83
107
|
|
84
|
-
if
|
85
|
-
|
86
|
-
|
87
|
-
|
108
|
+
if ctl_num == 1
|
109
|
+
unless tund
|
110
|
+
tund = new_a_tund( tun_addr, tun_ip_addr, orig_src_addr, dest_addr )
|
111
|
+
end
|
112
|
+
elsif ctl_num == 4
|
113
|
+
root_dest_addr = data[ 33, 16 ]
|
114
|
+
return unless Addrinfo.new( root_dest_addr ).ipv4?
|
88
115
|
|
89
|
-
|
90
|
-
src_addr = @halfs[ udp_addr ][ 0, 16 ]
|
91
|
-
dest_addr = @halfs[ udp_addr ][ 16, 16 ]
|
92
|
-
data = "#{ dest_addr }#{ data }"
|
93
|
-
@halfs.delete( udp_addr )
|
94
|
-
else
|
95
|
-
src_addr = data[ 0, 16 ]
|
96
|
-
dest_addr = data[ 16, 16 ]
|
97
|
-
data = data[ 16..-1 ]
|
98
|
-
end
|
116
|
+
root_tund = @tunds[ [ tun_ip_addr, orig_src_addr, root_dest_addr ].join ]
|
99
117
|
|
100
|
-
|
101
|
-
|
118
|
+
unless root_tund
|
119
|
+
puts "miss root tund? #{ Addrinfo.new( tun_ip_addr ).inspect } #{ Addrinfo.new( orig_src_addr ).inspect } #{ Addrinfo.new( root_dest_addr ).inspect }"
|
120
|
+
return
|
121
|
+
end
|
102
122
|
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
dest.bind( Socket.sockaddr_in( 0, '0.0.0.0' ) )
|
110
|
-
|
111
|
-
@dests[ us_addr ] = dest
|
112
|
-
@dest_infos[ dest ] = {
|
113
|
-
us_addr: us_addr,
|
114
|
-
udp_addr: udp_addr,
|
115
|
-
src_addr: src_addr,
|
116
|
-
wbuffs: [],
|
117
|
-
last_traff_at: Time.new
|
118
|
-
}
|
119
|
-
|
120
|
-
@roles[ dest ] = :dest
|
121
|
-
@reads << dest
|
123
|
+
if tund
|
124
|
+
tund_info = @tund_infos[ tund ]
|
125
|
+
tund_info[ :root_tund ] = root_tund
|
126
|
+
else
|
127
|
+
tund = new_a_tund( tun_addr, tun_ip_addr, orig_src_addr, dest_addr, root_tund )
|
128
|
+
end
|
122
129
|
end
|
123
130
|
|
124
|
-
|
125
|
-
|
126
|
-
|
131
|
+
tund_info = @tund_infos[ tund ]
|
132
|
+
tund_port = tund_info[ :port ]
|
133
|
+
|
134
|
+
# puts "debug send C: 2 (udpd > tun: tund port) -> n: tund_port -> tun_addr #{ tund_port } #{ addrinfo.inspect }"
|
135
|
+
@udpd_wbuffs << [ tun_addr, [ [ 2, tund_port ].pack( 'Cn' ), tun_addr ].join ]
|
136
|
+
|
137
|
+
unless @writes.include?( udpd )
|
138
|
+
@writes << udpd
|
139
|
+
end
|
127
140
|
end
|
128
141
|
|
129
|
-
def
|
130
|
-
data, addrinfo, rflags, *controls =
|
142
|
+
def read_tund( tund )
|
143
|
+
data, addrinfo, rflags, *controls = tund.recvmsg
|
144
|
+
from_addr = addrinfo.to_sockaddr
|
145
|
+
tund_info = @tund_infos[ tund ]
|
146
|
+
tund_info[ :last_traff_at ] = Time.new
|
147
|
+
|
148
|
+
if from_addr == tund_info[ :tun_addr ]
|
149
|
+
root_tund = tund_info[ :root_tund ]
|
150
|
+
|
151
|
+
if !tund_info[ :is_tunneled ]
|
152
|
+
tund_info[ :is_tunneled ] = true
|
153
|
+
|
154
|
+
if root_tund
|
155
|
+
# p2p tunnel paired
|
156
|
+
root_tund_info = @tund_infos[ root_tund ]
|
157
|
+
dest_rbuffs = root_tund_info[ :new_dest_rbuffs ].delete( tund_info[ :dest_addr ] )
|
158
|
+
|
159
|
+
if dest_rbuffs
|
160
|
+
# puts "debug #{ Addrinfo.new( tund_info[ :dest_addr ] ).inspect } dest_rbuffs #{ dest_rbuffs.inspect }"
|
161
|
+
tund_info[ :wbuffs ] = dest_rbuffs
|
162
|
+
add_write( tund )
|
163
|
+
end
|
164
|
+
|
165
|
+
if data.size == 1 && data[ 0 ].unpack( 'C' ).first == 5
|
166
|
+
puts "ignore C: 5 (hello) #{ Time.new }"
|
167
|
+
return
|
168
|
+
end
|
169
|
+
end
|
170
|
+
end
|
171
|
+
|
172
|
+
sender = root_tund || tund
|
173
|
+
sender.sendmsg( data, 0, tund_info[ :dest_addr ] )
|
174
|
+
|
175
|
+
if root_tund.nil? && !tund_info[ :is_dest_responsed ]
|
176
|
+
if tund_info[ :dest_wmemos ].size >= 10
|
177
|
+
tund_info[ :dest_wmemos ].clear
|
178
|
+
end
|
131
179
|
|
132
|
-
|
133
|
-
|
180
|
+
tund_info[ :dest_wmemos ] << data
|
181
|
+
end
|
182
|
+
elsif from_addr == tund_info[ :dest_addr ]
|
183
|
+
tund_info[ :is_dest_responsed ] = true
|
184
|
+
add_write( tund, data )
|
185
|
+
else
|
186
|
+
# p2p input
|
187
|
+
# puts "debug tund recv #{ data.inspect } from #{ Addrinfo.new( from_addr ).inspect }"
|
188
|
+
chain_tund = @tunds[ [ tund_info[ :tun_ip_addr ], tund_info[ :orig_src_addr ], from_addr ].join ]
|
134
189
|
|
135
|
-
|
136
|
-
|
137
|
-
|
190
|
+
unless chain_tund
|
191
|
+
unless tund_info[ :new_dest_rbuffs ].include?( from_addr )
|
192
|
+
tund_info[ :new_dest_rbuffs ][ from_addr ] = []
|
193
|
+
end
|
194
|
+
|
195
|
+
tund_info[ :new_dest_rbuffs ][ from_addr ] << data
|
196
|
+
|
197
|
+
# puts "debug send C: 3 (udpd > tun: req a chain tun) -> new_dest_addr -> root_dest_addr #{ Addrinfo.new( from_addr ).inspect } #{ Addrinfo.new( tund_info[ :dest_addr ] ).inspect }"
|
198
|
+
msg = [ [ 3 ].pack( 'C' ), from_addr, tund_info[ :dest_addr ] ].join
|
199
|
+
@udpd.sendmsg( msg, 0, tund_info[ :tun_addr ] )
|
200
|
+
return
|
201
|
+
end
|
202
|
+
|
203
|
+
chain_tund_info = @tund_infos[ chain_tund ]
|
204
|
+
|
205
|
+
unless chain_tund_info[ :root_tund ]
|
206
|
+
# p2p paired
|
207
|
+
chain_tund_info[ :root_tund ] = tund
|
208
|
+
|
209
|
+
if chain_tund_info[ :dest_wmemos ].size > 0
|
210
|
+
chain_tund_info[ :dest_wmemos ].each do | wmemo |
|
211
|
+
# puts "debug send wmemo #{ wmemo.inspect } to #{ Addrinfo.new( from_addr ).inspect }"
|
212
|
+
tund.sendmsg( wmemo, 0, from_addr )
|
213
|
+
end
|
214
|
+
|
215
|
+
chain_tund_info[ :dest_wmemos ].clear
|
216
|
+
end
|
217
|
+
end
|
218
|
+
|
219
|
+
add_write( chain_tund, data )
|
220
|
+
end
|
138
221
|
end
|
139
222
|
|
140
|
-
def
|
141
|
-
if @
|
142
|
-
|
223
|
+
def write_udpd( udpd )
|
224
|
+
if @udpd_wbuffs.empty?
|
225
|
+
@writes.delete( udpd )
|
143
226
|
return
|
144
227
|
end
|
145
228
|
|
146
|
-
|
147
|
-
|
229
|
+
tun_addr, ctlmsg = @udpd_wbuffs.shift
|
230
|
+
udpd.sendmsg( ctlmsg, 0, tun_addr )
|
231
|
+
end
|
148
232
|
|
149
|
-
|
150
|
-
|
233
|
+
def write_tund( tund )
|
234
|
+
if @closings.include?( tund )
|
235
|
+
close_tund( tund )
|
151
236
|
return
|
152
237
|
end
|
153
238
|
|
154
|
-
|
155
|
-
data = data[ 16..-1 ]
|
239
|
+
tund_info = @tund_infos[ tund ]
|
156
240
|
|
157
|
-
|
158
|
-
|
159
|
-
rescue Errno::EACCES, Errno::EINTR => e
|
160
|
-
puts "dest sendmsg #{ e.class } #{ Time.new }"
|
161
|
-
add_closing( dest )
|
241
|
+
if tund_info[ :wbuffs ].empty?
|
242
|
+
@writes.delete( tund )
|
162
243
|
return
|
163
244
|
end
|
164
245
|
|
165
|
-
|
246
|
+
data = tund_info[ :wbuffs ].shift
|
247
|
+
tund.sendmsg( data, 0, tund_info[ :tun_addr ] )
|
166
248
|
end
|
167
249
|
|
168
|
-
def add_write(
|
169
|
-
|
170
|
-
|
250
|
+
def add_write( tund, data = nil )
|
251
|
+
tund_info = @tund_infos[ tund ]
|
252
|
+
|
253
|
+
if data
|
254
|
+
tund_info[ :wbuffs ] << data
|
255
|
+
end
|
256
|
+
|
257
|
+
if tund_info[ :tun_addr ] && !@writes.include?( tund )
|
258
|
+
@writes << tund
|
171
259
|
end
|
172
260
|
end
|
173
261
|
|
174
|
-
def add_closing(
|
175
|
-
unless @closings.include?(
|
176
|
-
@closings <<
|
262
|
+
def add_closing( tund )
|
263
|
+
unless @closings.include?( tund )
|
264
|
+
@closings << tund
|
177
265
|
end
|
178
266
|
|
179
|
-
add_write(
|
267
|
+
add_write( tund )
|
180
268
|
end
|
181
269
|
|
182
|
-
def
|
183
|
-
|
184
|
-
@reads.delete(
|
185
|
-
@writes.delete(
|
186
|
-
@closings.delete(
|
187
|
-
@roles.delete(
|
188
|
-
|
189
|
-
@
|
270
|
+
def close_tund( tund )
|
271
|
+
tund.close
|
272
|
+
@reads.delete( tund )
|
273
|
+
@writes.delete( tund )
|
274
|
+
@closings.delete( tund )
|
275
|
+
@roles.delete( tund )
|
276
|
+
tund_info = @tund_infos.delete( tund )
|
277
|
+
@tunds.delete( [ tund_info[ :tun_ip_addr ], tund_info[ :orig_src_addr ], tund_info[ :dest_addr ] ].join )
|
190
278
|
end
|
191
279
|
|
192
|
-
def
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
280
|
+
def new_a_tund( tun_addr, tun_ip_addr, orig_src_addr, dest_addr, root_tund = nil )
|
281
|
+
tund = Socket.new( Socket::AF_INET, Socket::SOCK_DGRAM, 0 )
|
282
|
+
tund.setsockopt( Socket::SOL_SOCKET, Socket::SO_REUSEPORT, 1 )
|
283
|
+
tund.bind( Socket.sockaddr_in( 0, '0.0.0.0' ) )
|
284
|
+
tund_port = tund.local_address.ip_unpack.last
|
285
|
+
|
286
|
+
@tunds[ [ tun_ip_addr, orig_src_addr, dest_addr ].join ] = tund
|
287
|
+
@tund_infos[ tund ] = {
|
288
|
+
port: tund_port,
|
289
|
+
is_tunneled: false,
|
290
|
+
tun_addr: tun_addr,
|
291
|
+
tun_ip_addr: tun_ip_addr,
|
292
|
+
orig_src_addr: orig_src_addr,
|
293
|
+
dest_addr: dest_addr,
|
294
|
+
root_tund: root_tund,
|
295
|
+
wbuffs: [],
|
296
|
+
is_dest_responsed: root_tund ? true : false,
|
297
|
+
dest_wmemos: [],
|
298
|
+
new_dest_rbuffs: {},
|
299
|
+
last_traff_at: Time.new
|
300
|
+
}
|
301
|
+
|
302
|
+
@roles[ tund ] = :tund
|
303
|
+
@reads << tund
|
304
|
+
|
305
|
+
tund
|
201
306
|
end
|
202
307
|
|
203
308
|
def loop_expire
|
@@ -208,9 +313,9 @@ module Girl
|
|
208
313
|
@mutex.synchronize do
|
209
314
|
now = Time.new
|
210
315
|
|
211
|
-
@
|
212
|
-
if now -
|
213
|
-
@ctlw.write(
|
316
|
+
@tund_infos.values.each do | tund_info |
|
317
|
+
if now - tund_info[ :last_traff_at ] > 1800
|
318
|
+
@ctlw.write( [ tund_info[ :tun_ip_addr ], tund_info[ :orig_src_addr ], tund_info[ :dest_addr ] ].join )
|
214
319
|
end
|
215
320
|
end
|
216
321
|
end
|
data/lib/girl/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: girl
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.54.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- takafan
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2020-
|
11
|
+
date: 2020-04-02 00:00:00.000000000 Z
|
12
12
|
dependencies: []
|
13
13
|
description: while internet is evil, here's a girl.
|
14
14
|
email:
|