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.

Files changed (5) hide show
  1. checksums.yaml +4 -4
  2. data/lib/girl/udp.rb +229 -119
  3. data/lib/girl/udpd.rb +210 -105
  4. data/lib/girl/version.rb +1 -1
  5. metadata +2 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 93fdfe2ce9f04aadda128b2ea4fa78d53370d240b7b8bf8ec7599a4269dce015
4
- data.tar.gz: 8e4dd7830bd3575d7dbbd38c767b48d467cd135d7e804d4482ead4afd8d783d7
3
+ metadata.gz: 19acd0601b223880d31ac0294928830d0a683e419bce6da31712914bebc7b65d
4
+ data.tar.gz: 8b112d1eec1f6a83851e8b12e546217c8aeb59f9c743e56d600a23c2f5fc333e
5
5
  SHA512:
6
- metadata.gz: b81316544189b48c6767010096eaa47df8a492b7f1e381945fee069af228fb6dfdf60e82b217a60292a40615fbbb0bea7e8448a8c57318ad628a698701ddc35e
7
- data.tar.gz: d182a4d6509f321098520778d81b37189e29de591247239fbcc28027c974ca5647fc9a37c9a174dcfd1bf8510db8c60ae8316f4af9296f77aab9f87fb1726dbc
6
+ metadata.gz: d9bc77923d0a6e1637cd3b29c2f15aca7d882bf7b6b7501c51cf0fac529244e63e2ce4f8ca47594886d598479eaf3f545801a9f5fdb5fd00075a520cd69db86f
7
+ data.tar.gz: e57bdec56fb691207a9f4c1d47622c0f64ef9d4d3b703afba745281e41c50ae84825809af59fc84b1740eceb525a063b8ed3be130295af3725751518c9c44b3e
@@ -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
- @udp = udp
37
- @reads = [ ctlr, redir, udp ]
69
+ @reads = [ ctlr, redir ]
38
70
  @writes = []
39
71
  @closings = []
40
72
  @roles = {
41
- ctlr => :ctlr, # :ctlr / :redir / :udp / :src
42
- redir => :redir,
43
- udp => :udp
73
+ ctlr => :ctlr, # :ctlr / :redir / :tun
74
+ redir => :redir
44
75
  }
45
- @srcs = {} # sd_addr => src
46
- @src_infos = {} # src => {}
47
- # sd_addr: [ src_addr, dest_addr ].join
48
- # src_addr: src_addr
49
- # dest_addr: dest_addr
50
- # last_traff_at: now
51
- @half = nil # [ dest_addr, src_addr ].join
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 :udp
68
- read_udp( sock )
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
- write_src( sock )
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
- sd_addr = ctlr.read( 32 )
89
- src = @srcs[ sd_addr ]
127
+ od_addr = ctlr.read( 32 )
128
+ tun = @tuns[ od_addr ]
90
129
 
91
- if src
92
- add_closing( src )
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
- rows = IO.readlines( '/proc/net/nf_conntrack' ).reverse.map{ | line | line.split( ' ' ) }
101
- row = rows.find{ | row | row[ 9 ] == '[UNREPLIED]' && row[ 2 ] == 'udp' && row[ 7 ].split( '=' )[ 1 ].to_i == addrinfo.ip_port && row[ 5 ].split( '=' )[ 1 ] == addrinfo.ip_address }
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
- dest_addr = Socket.sockaddr_in( row[ 8 ].split( '=' )[ 1 ].to_i, row[ 6 ].split( '=' )[ 1 ] )
109
- sendmsg_to_udpd( "#{ src_addr }#{ dest_addr }#{ data }" )
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 read_udp( udp )
113
- data, addrinfo, rflags, *controls = udp.recvmsg
114
- return if data.size < 32
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 @half.nil? && data.size == 32
117
- @half = data
118
- return
119
- end
192
+ if from_addr == @udpd_addr
193
+ ctl_num = data[ 0 ].unpack( 'C' ).first
120
194
 
121
- if @half
122
- dest_addr = @half[ 0, 16 ]
123
- src_addr = @half[ 16, 16 ]
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
- sd_addr = [ src_addr, dest_addr ].join
132
- src = @srcs[ sd_addr ]
133
-
134
- unless src
135
- src = Socket.new( Socket::AF_INET, Socket::SOCK_DGRAM, 0 )
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
- src_info = @src_infos[ src ]
153
- src_info[ :wbuffs ] << data
154
- add_write( src )
155
- end
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
- def read_src( src )
158
- data, addrinfo, rflags, *controls = src.recvmsg
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
- src_info = @src_infos[ src ]
161
- return unless src_info
217
+ unless chain_tun
218
+ chain_tun = new_a_tun( orig_src_addr, new_dest_addr )
219
+ end
162
220
 
163
- src_info[ :last_traff_at ] = Time.new
164
- src_addr = addrinfo.to_sockaddr
165
- sendmsg_to_udpd( "#{ src_addr }#{ src_info[ :dest_addr ] }#{ data }" )
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 write_src( src )
169
- if @closings.include?( src )
170
- close_src( src )
246
+ def write_tun( tun )
247
+ if @closings.include?( tun )
248
+ close_tun( tun )
171
249
  return
172
250
  end
173
251
 
174
- src_info = @src_infos[ src ]
175
- data = src_info[ :wbuffs ].shift
252
+ tun_info = @tun_infos[ tun ]
253
+ ctlmsg = tun_info[ :ctlmsgs ].shift
176
254
 
177
- unless data
178
- @writes.delete( src )
255
+ if ctlmsg
256
+ tun.sendmsg( ctlmsg, 0, @udpd_addr )
179
257
  return
180
258
  end
181
259
 
182
- begin
183
- src.sendmsg( data, 0, src_info[ :src_addr ] )
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
- src_info[ :last_traff_at ] = Time.new
265
+ data = tun_info[ :wbuffs ].shift
266
+ tun.sendmsg( data, 0, tun_info[ :tund_addr ] )
191
267
  end
192
268
 
193
- def add_write( src )
194
- unless @writes.include?( src )
195
- @writes << src
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 add_closing( src )
200
- unless @closings.include?( src )
201
- @closings << src
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
- add_write( src )
285
+ unless @writes.include?( tun )
286
+ @writes << tun
287
+ end
205
288
  end
206
289
 
207
- def close_src( src )
208
- src.close
209
- @reads.delete( src )
210
- @writes.delete( src )
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 sendmsg_to_udpd( data )
218
- begin
219
- @udp.sendmsg( data, 0, @udpd_addr )
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
- @src_infos.values.each do | src_info |
237
- if now - src_info[ :last_traff_at ] > 1800
238
- @ctlw.write( src_info[ :sd_addr ] )
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
@@ -22,16 +22,25 @@ module Girl
22
22
  @writes = []
23
23
  @closings = []
24
24
  @roles = {
25
- ctlr => :ctlr, # :ctlr / :udpd / :dest
25
+ ctlr => :ctlr, # :ctlr / :udpd / :tund
26
26
  udpd => :udpd
27
27
  }
28
- @dests = {} # us_addr => dest
29
- @dest_infos = {} # dest => {}
30
- # us_addr: [ udp_addr, src_addr ].join
31
- # udp_addr: udp_addr
32
- # src_addr: src_addr
33
- # last_traff_at: now
34
- @halfs = {} # udp_addr => [ src_addr, dest_addr ].join
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 :dest
51
- read_dest( sock )
59
+ when :tund
60
+ read_tund( sock )
52
61
  end
53
62
  end
54
63
 
55
64
  ws.each do | sock |
56
- write_dest( sock )
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
- us_addr = ctlr.read( 32 )
70
- dest = @dests[ us_addr ]
83
+ tod_addr = ctlr.read( 48 )
84
+ tund = @tunds[ tod_addr ]
71
85
 
72
- if dest
73
- # puts "debug expire dest #{ us_addr.inspect } #{ Time.new }"
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
- return if data.size < 32
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
- udp_addr = addrinfo.to_sockaddr
106
+ tund = @tunds[ [ tun_ip_addr, orig_src_addr, dest_addr ].join ]
83
107
 
84
- if @halfs[ udp_addr ].nil? && data.size == 32
85
- @halfs[ udp_addr ] = data
86
- return
87
- end
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
- if @halfs[ udp_addr ]
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
- return unless Addrinfo.new( src_addr ).ipv4?
101
- return unless Addrinfo.new( dest_addr ).ipv4?
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
- us_addr = [ udp_addr, src_addr ].join
104
- dest = @dests[ us_addr ]
105
-
106
- unless dest
107
- dest = Socket.new( Socket::AF_INET, Socket::SOCK_DGRAM, 0 )
108
- dest.setsockopt( Socket::SOL_SOCKET, Socket::SO_REUSEPORT, 1 )
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
- dest_info = @dest_infos[ dest ]
125
- dest_info[ :wbuffs ] << data
126
- add_write( dest )
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 read_dest( dest )
130
- data, addrinfo, rflags, *controls = dest.recvmsg
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
- dest_info = @dest_infos[ dest ]
133
- return unless dest_info
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
- dest_info[ :last_traff_at ] = Time.new
136
- dest_addr = addrinfo.to_sockaddr
137
- sendmsg_to_udp( "#{ dest_addr }#{ dest_info[ :src_addr ] }#{ data }", dest_info[ :udp_addr ] )
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 write_dest( dest )
141
- if @closings.include?( dest )
142
- close_dest( dest )
223
+ def write_udpd( udpd )
224
+ if @udpd_wbuffs.empty?
225
+ @writes.delete( udpd )
143
226
  return
144
227
  end
145
228
 
146
- dest_info = @dest_infos[ dest ]
147
- data = dest_info[ :wbuffs ].shift
229
+ tun_addr, ctlmsg = @udpd_wbuffs.shift
230
+ udpd.sendmsg( ctlmsg, 0, tun_addr )
231
+ end
148
232
 
149
- unless data
150
- @writes.delete( dest )
233
+ def write_tund( tund )
234
+ if @closings.include?( tund )
235
+ close_tund( tund )
151
236
  return
152
237
  end
153
238
 
154
- dest_addr = data[ 0, 16 ]
155
- data = data[ 16..-1 ]
239
+ tund_info = @tund_infos[ tund ]
156
240
 
157
- begin
158
- dest.sendmsg( data, 0, dest_addr )
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
- dest_info[ :last_traff_at ] = Time.new
246
+ data = tund_info[ :wbuffs ].shift
247
+ tund.sendmsg( data, 0, tund_info[ :tun_addr ] )
166
248
  end
167
249
 
168
- def add_write( dest )
169
- unless @writes.include?( dest )
170
- @writes << dest
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( dest )
175
- unless @closings.include?( dest )
176
- @closings << dest
262
+ def add_closing( tund )
263
+ unless @closings.include?( tund )
264
+ @closings << tund
177
265
  end
178
266
 
179
- add_write( dest )
267
+ add_write( tund )
180
268
  end
181
269
 
182
- def close_dest( dest )
183
- dest.close
184
- @reads.delete( dest )
185
- @writes.delete( dest )
186
- @closings.delete( dest )
187
- @roles.delete( dest )
188
- dest_info = @dest_infos.delete( dest )
189
- @dests.delete( dest_info[ :us_addr ] )
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 sendmsg_to_udp( data, udp_addr )
193
- begin
194
- @udpd.sendmsg( data, 0, udp_addr )
195
- rescue Errno::EMSGSIZE => e
196
- puts "#{ e.class } #{ Time.new }"
197
- [ data[ 0, 32 ], data[ 32..-1 ] ].each do | part |
198
- @udpd.sendmsg( part, 0, udp_addr )
199
- end
200
- end
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
- @dest_infos.values.each do | dest_info |
212
- if now - dest_info[ :last_traff_at ] > 1800
213
- @ctlw.write( dest_info[ :us_addr ] )
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
@@ -1,3 +1,3 @@
1
1
  module Girl
2
- VERSION = '0.53.0'.freeze
2
+ VERSION = '0.54.0'.freeze
3
3
  end
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.53.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-03-26 00:00:00.000000000 Z
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: