oversip_p 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (132) hide show
  1. checksums.yaml +7 -0
  2. data/AUTHORS +22 -0
  3. data/LICENSE +25 -0
  4. data/README.md +43 -0
  5. data/Rakefile +54 -0
  6. data/bin/oversip +184 -0
  7. data/etc/oversip.conf +274 -0
  8. data/etc/proxies.conf +145 -0
  9. data/etc/server.rb +315 -0
  10. data/etc/tls/ca/cacert.pem +3894 -0
  11. data/etc/tls/demo-tls.oversip.net.crt +17 -0
  12. data/etc/tls/demo-tls.oversip.net.key +15 -0
  13. data/etc/tls/upgrade-cacert.sh +12 -0
  14. data/etc/tls/utils/create-cert.rb +162 -0
  15. data/etc/tls/utils/get-sip-identities.rb +95 -0
  16. data/ext/common/c_util.h +74 -0
  17. data/ext/common/ruby_c_util.h +88 -0
  18. data/ext/sip_parser/common_headers.h +210 -0
  19. data/ext/sip_parser/ext_help.h +18 -0
  20. data/ext/sip_parser/extconf.rb +3 -0
  21. data/ext/sip_parser/sip_message_parser.c +29741 -0
  22. data/ext/sip_parser/sip_parser.h +250 -0
  23. data/ext/sip_parser/sip_parser_ruby.c +1370 -0
  24. data/ext/sip_parser/sip_uri_parser.c +39699 -0
  25. data/ext/stud/extconf.rb +43 -0
  26. data/ext/stun/ext_help.h +16 -0
  27. data/ext/stun/extconf.rb +3 -0
  28. data/ext/stun/stun_ruby.c +394 -0
  29. data/ext/utils/ext_help.h +14 -0
  30. data/ext/utils/extconf.rb +3 -0
  31. data/ext/utils/haproxy_protocol.c +6163 -0
  32. data/ext/utils/haproxy_protocol.h +27 -0
  33. data/ext/utils/ip_utils.c +5952 -0
  34. data/ext/utils/ip_utils.h +64 -0
  35. data/ext/utils/outbound_utils.c +3227 -0
  36. data/ext/utils/outbound_utils.h +27 -0
  37. data/ext/utils/utils_ruby.c +392 -0
  38. data/ext/utils/utils_ruby.h +76 -0
  39. data/ext/websocket_framing_utils/ext_help.h +18 -0
  40. data/ext/websocket_framing_utils/extconf.rb +3 -0
  41. data/ext/websocket_framing_utils/ws_framing_utils.h +47 -0
  42. data/ext/websocket_framing_utils/ws_framing_utils_ruby.c +135 -0
  43. data/ext/websocket_http_parser/ext_help.h +18 -0
  44. data/ext/websocket_http_parser/extconf.rb +3 -0
  45. data/ext/websocket_http_parser/ws_http_parser.c +1635 -0
  46. data/ext/websocket_http_parser/ws_http_parser.h +87 -0
  47. data/ext/websocket_http_parser/ws_http_parser_ruby.c +630 -0
  48. data/lib/oversip/config.rb +597 -0
  49. data/lib/oversip/config_validators.rb +126 -0
  50. data/lib/oversip/default_server.rb +52 -0
  51. data/lib/oversip/errors.rb +10 -0
  52. data/lib/oversip/fiber_pool.rb +56 -0
  53. data/lib/oversip/launcher.rb +635 -0
  54. data/lib/oversip/logger.rb +84 -0
  55. data/lib/oversip/modules/outbound_mangling.rb +56 -0
  56. data/lib/oversip/modules/user_assertion.rb +73 -0
  57. data/lib/oversip/proxies_config.rb +189 -0
  58. data/lib/oversip/ruby_ext/eventmachine.rb +38 -0
  59. data/lib/oversip/sip/client.rb +428 -0
  60. data/lib/oversip/sip/client_transaction.rb +586 -0
  61. data/lib/oversip/sip/constants.rb +88 -0
  62. data/lib/oversip/sip/core.rb +217 -0
  63. data/lib/oversip/sip/launcher.rb +221 -0
  64. data/lib/oversip/sip/listeners/connection.rb +54 -0
  65. data/lib/oversip/sip/listeners/ipv4_tcp_client.rb +21 -0
  66. data/lib/oversip/sip/listeners/ipv4_tcp_server.rb +22 -0
  67. data/lib/oversip/sip/listeners/ipv4_tls_client.rb +21 -0
  68. data/lib/oversip/sip/listeners/ipv4_tls_server.rb +22 -0
  69. data/lib/oversip/sip/listeners/ipv4_tls_tunnel_server.rb +22 -0
  70. data/lib/oversip/sip/listeners/ipv4_udp_server.rb +21 -0
  71. data/lib/oversip/sip/listeners/ipv6_tcp_client.rb +21 -0
  72. data/lib/oversip/sip/listeners/ipv6_tcp_server.rb +22 -0
  73. data/lib/oversip/sip/listeners/ipv6_tls_client.rb +21 -0
  74. data/lib/oversip/sip/listeners/ipv6_tls_server.rb +22 -0
  75. data/lib/oversip/sip/listeners/ipv6_tls_tunnel_server.rb +22 -0
  76. data/lib/oversip/sip/listeners/ipv6_udp_server.rb +21 -0
  77. data/lib/oversip/sip/listeners/tcp_client.rb +97 -0
  78. data/lib/oversip/sip/listeners/tcp_connection.rb +202 -0
  79. data/lib/oversip/sip/listeners/tcp_server.rb +71 -0
  80. data/lib/oversip/sip/listeners/tls_client.rb +125 -0
  81. data/lib/oversip/sip/listeners/tls_server.rb +88 -0
  82. data/lib/oversip/sip/listeners/tls_tunnel_connection.rb +89 -0
  83. data/lib/oversip/sip/listeners/tls_tunnel_server.rb +61 -0
  84. data/lib/oversip/sip/listeners/udp_connection.rb +214 -0
  85. data/lib/oversip/sip/listeners.rb +24 -0
  86. data/lib/oversip/sip/message.rb +177 -0
  87. data/lib/oversip/sip/message_processor.rb +213 -0
  88. data/lib/oversip/sip/name_addr.rb +51 -0
  89. data/lib/oversip/sip/proxy.rb +324 -0
  90. data/lib/oversip/sip/request.rb +179 -0
  91. data/lib/oversip/sip/response.rb +37 -0
  92. data/lib/oversip/sip/rfc3263.rb +643 -0
  93. data/lib/oversip/sip/server_transaction.rb +295 -0
  94. data/lib/oversip/sip/sip.rb +76 -0
  95. data/lib/oversip/sip/tags.rb +39 -0
  96. data/lib/oversip/sip/timers.rb +55 -0
  97. data/lib/oversip/sip/transport_manager.rb +130 -0
  98. data/lib/oversip/sip/uac.rb +89 -0
  99. data/lib/oversip/sip/uac_request.rb +84 -0
  100. data/lib/oversip/sip/uri.rb +208 -0
  101. data/lib/oversip/syslog.rb +68 -0
  102. data/lib/oversip/system_callbacks.rb +45 -0
  103. data/lib/oversip/tls.rb +172 -0
  104. data/lib/oversip/utils.rb +30 -0
  105. data/lib/oversip/version.rb +21 -0
  106. data/lib/oversip/websocket/constants.rb +55 -0
  107. data/lib/oversip/websocket/http_request.rb +59 -0
  108. data/lib/oversip/websocket/launcher.rb +183 -0
  109. data/lib/oversip/websocket/listeners/connection.rb +51 -0
  110. data/lib/oversip/websocket/listeners/ipv4_ws_server.rb +22 -0
  111. data/lib/oversip/websocket/listeners/ipv4_wss_server.rb +22 -0
  112. data/lib/oversip/websocket/listeners/ipv4_wss_tunnel_server.rb +22 -0
  113. data/lib/oversip/websocket/listeners/ipv6_ws_server.rb +22 -0
  114. data/lib/oversip/websocket/listeners/ipv6_wss_server.rb +22 -0
  115. data/lib/oversip/websocket/listeners/ipv6_wss_tunnel_server.rb +22 -0
  116. data/lib/oversip/websocket/listeners/ws_server.rb +331 -0
  117. data/lib/oversip/websocket/listeners/wss_server.rb +88 -0
  118. data/lib/oversip/websocket/listeners/wss_tunnel_server.rb +133 -0
  119. data/lib/oversip/websocket/listeners.rb +13 -0
  120. data/lib/oversip/websocket/websocket.rb +13 -0
  121. data/lib/oversip/websocket/ws_framing.rb +545 -0
  122. data/lib/oversip/websocket/ws_sip_app.rb +120 -0
  123. data/lib/oversip.rb +127 -0
  124. data/test/oversip_test_helper.rb +19 -0
  125. data/test/test_http_parser.rb +73 -0
  126. data/test/test_name_addr.rb +27 -0
  127. data/test/test_name_addr_parser.rb +24 -0
  128. data/test/test_sip_message_parser.rb +168 -0
  129. data/test/test_sip_uri_parser.rb +56 -0
  130. data/test/test_uri.rb +68 -0
  131. data/thirdparty/stud/stud.tar.gz +0 -0
  132. metadata +334 -0
@@ -0,0 +1,27 @@
1
+ #ifndef outbound_utils_h
2
+ #define outbound_utils_h
3
+
4
+
5
+ #include <sys/types.h>
6
+
7
+
8
+ enum enum_outbound_udp_flow_token_ip_type {
9
+ outbound_udp_flow_token_ip_type_ipv4 = 1,
10
+ outbound_udp_flow_token_ip_type_ipv6
11
+ };
12
+
13
+
14
+ typedef struct struct_outbound_udp_flow_token {
15
+ unsigned short int valid;
16
+ enum enum_outbound_udp_flow_token_ip_type ip_type;
17
+ size_t ip_s;
18
+ size_t ip_len;
19
+ size_t port_s;
20
+ size_t port_len;
21
+ } struct_outbound_udp_flow_token;
22
+
23
+
24
+ struct_outbound_udp_flow_token outbound_udp_flow_token_parser_execute(const char *str, size_t len);
25
+
26
+
27
+ #endif
@@ -0,0 +1,392 @@
1
+ #include <ruby.h>
2
+ #include "ext_help.h"
3
+ #include "ip_utils.h"
4
+ #include "utils_ruby.h"
5
+ #include "../common/c_util.h"
6
+
7
+
8
+ static VALUE mOverSIP;
9
+ static VALUE mUtils;
10
+
11
+ static VALUE symbol_ipv4;
12
+ static VALUE symbol_ipv6;
13
+ static VALUE symbol_ipv6_reference;
14
+
15
+
16
+
17
+ /*
18
+ * Ruby functions.
19
+ */
20
+
21
+ VALUE Utils_is_ip(VALUE self, VALUE string)
22
+ {
23
+ TRACE();
24
+ char *str;
25
+ long len;
26
+
27
+ if (TYPE(string) != T_STRING)
28
+ rb_raise(rb_eTypeError, "Argument must be a String");
29
+
30
+ str = RSTRING_PTR(string);
31
+ len = RSTRING_LEN(string);
32
+
33
+ if (utils_ip_parser_execute(str, len) != ip_type_error)
34
+ return Qtrue;
35
+ else
36
+ return Qfalse;
37
+ }
38
+
39
+
40
+ VALUE Utils_is_pure_ip(VALUE self, VALUE string)
41
+ {
42
+ TRACE();
43
+ char *str;
44
+ long len;
45
+
46
+ if (TYPE(string) != T_STRING)
47
+ rb_raise(rb_eTypeError, "Argument must be a String");
48
+
49
+ str = RSTRING_PTR(string);
50
+ len = RSTRING_LEN(string);
51
+
52
+ switch(utils_ip_parser_execute(str, len)) {
53
+ case(ip_type_ipv4):
54
+ return Qtrue;
55
+ break;
56
+ case(ip_type_ipv6):
57
+ return Qtrue;
58
+ break;
59
+ default:
60
+ return Qfalse;
61
+ break;
62
+ }
63
+ }
64
+
65
+
66
+ VALUE Utils_ip_type(VALUE self, VALUE string)
67
+ {
68
+ TRACE();
69
+ char *str;
70
+ long len;
71
+
72
+ if (TYPE(string) != T_STRING)
73
+ rb_raise(rb_eTypeError, "Argument must be a String");
74
+
75
+ str = RSTRING_PTR(string);
76
+ len = RSTRING_LEN(string);
77
+
78
+ switch(utils_ip_parser_execute(str, len)) {
79
+ case(ip_type_ipv4):
80
+ return symbol_ipv4;
81
+ break;
82
+ case(ip_type_ipv6):
83
+ return symbol_ipv6;
84
+ break;
85
+ case(ip_type_ipv6_reference):
86
+ return symbol_ipv6_reference;
87
+ break;
88
+ default:
89
+ return Qfalse;
90
+ break;
91
+ }
92
+ }
93
+
94
+
95
+ /*
96
+ * Returns true if both IP's are equal (binary comparison).
97
+ * Returns false if both IP's are not equal.
98
+ * Returns nil if at least one of the IP's is not valid IPv4, IPv6 or IPv6 reference.
99
+ * This function also allows comparing an IPv6 with an IPv6 reference.
100
+ */
101
+ VALUE Utils_compare_ips(VALUE self, VALUE string1, VALUE string2)
102
+ {
103
+ TRACE();
104
+ char *str1, *str2;
105
+ long len1, len2;
106
+ enum enum_ip_type ip1_type, ip2_type;
107
+
108
+ if (TYPE(string1) != T_STRING || TYPE(string2) != T_STRING)
109
+ rb_raise(rb_eTypeError, "Arguments must be two String");
110
+
111
+ str1 = RSTRING_PTR(string1);
112
+ len1 = RSTRING_LEN(string1);
113
+ str2 = RSTRING_PTR(string2);
114
+ len2 = RSTRING_LEN(string2);
115
+
116
+ switch(ip1_type = utils_ip_parser_execute(str1, len1)) {
117
+ case(ip_type_error):
118
+ return Qnil;
119
+ break;
120
+ case(ip_type_ipv6_reference):
121
+ str1 += 1;
122
+ len1 -= 2;
123
+ ip1_type = ip_type_ipv6;
124
+ break;
125
+ default:
126
+ break;
127
+ }
128
+ switch(ip2_type = utils_ip_parser_execute(str2, len2)) {
129
+ case(ip_type_error):
130
+ return Qnil;
131
+ break;
132
+ case(ip_type_ipv6_reference):
133
+ str2 += 1;
134
+ len2 -= 2;
135
+ ip2_type = ip_type_ipv6;
136
+ break;
137
+ default:
138
+ break;
139
+ }
140
+
141
+ if (utils_compare_pure_ips(str1, len1, ip1_type, str2, len2, ip2_type))
142
+ return Qtrue;
143
+ else
144
+ return Qfalse;
145
+ }
146
+
147
+
148
+ /*
149
+ * Returns true if both IP's are equal (binary comparison).
150
+ * Returns false if both IP's are not equal.
151
+ * Returns nil if at least one of the IP's is not valid IPv4 or IPv6.
152
+ * This function does not allow comparing an IPv6 with an IPv6 reference.
153
+ */
154
+ VALUE Utils_compare_pure_ips(VALUE self, VALUE string1, VALUE string2)
155
+ {
156
+ TRACE();
157
+ char *str1, *str2;
158
+ long len1, len2;
159
+ enum enum_ip_type ip1_type, ip2_type;
160
+
161
+ if (TYPE(string1) != T_STRING || TYPE(string2) != T_STRING)
162
+ rb_raise(rb_eTypeError, "Arguments must be two String");
163
+
164
+ str1 = RSTRING_PTR(string1);
165
+ len1 = RSTRING_LEN(string1);
166
+ str2 = RSTRING_PTR(string2);
167
+ len2 = RSTRING_LEN(string2);
168
+
169
+ switch(ip1_type = utils_ip_parser_execute(str1, len1)) {
170
+ case(ip_type_error):
171
+ return Qnil;
172
+ break;
173
+ case(ip_type_ipv6_reference):
174
+ return Qnil;
175
+ break;
176
+ default:
177
+ break;
178
+ }
179
+ switch(ip2_type = utils_ip_parser_execute(str2, len2)) {
180
+ case(ip_type_error):
181
+ return Qnil;
182
+ break;
183
+ case(ip_type_ipv6_reference):
184
+ return Qnil;
185
+ break;
186
+ default:
187
+ break;
188
+ }
189
+
190
+ if (utils_compare_pure_ips(str1, len1, ip1_type, str2, len2, ip2_type))
191
+ return Qtrue;
192
+ else
193
+ return Qfalse;
194
+ }
195
+
196
+
197
+ /*
198
+ * Returns the normalized printable string of the given IPv6.
199
+ * - First argument is a string to normalize. It must be a valid IPv6 or
200
+ * IPv6 reference. If not, the method returns false.
201
+ * - Second argument is optional. If true, returned value is a pure IPv6 even
202
+ * if the first argument is a IPv6 reference.
203
+ */
204
+ VALUE Utils_normalize_ipv6(int argc, VALUE *argv, VALUE self)
205
+ {
206
+ TRACE();
207
+ VALUE string;
208
+ int force_pure_ipv6 = 0;
209
+
210
+ if (argc == 0 || argc > 2)
211
+ rb_raise(rb_eTypeError, "Wrong number of arguments (pass one or two)");
212
+
213
+ string = argv[0];
214
+ if (TYPE(string) != T_STRING)
215
+ rb_raise(rb_eTypeError, "First argument must be a String");
216
+
217
+ if (argc == 2 && TYPE(argv[1]) != T_NIL && TYPE(argv[1]) != T_FALSE)
218
+ force_pure_ipv6 = 1;
219
+
220
+ return utils_normalize_ipv6(string, force_pure_ipv6);
221
+ }
222
+
223
+
224
+ /*
225
+ * Returns the normalized printable string of the given IPv4 or IPv6.
226
+ * - First argument is a string to normalize. It must be a valid IPv4, IPv6 or
227
+ * IPv6 reference. If not, the method returns the string itself.
228
+ * - Second argument is the type of host (:ipv4, :ipv6, :ipv6_reference or :domain).
229
+ * - Third argument is optional. If true, returned value is a pure IPv6 even
230
+ * if the first argument is a IPv6 reference.
231
+ *
232
+ * TODO: Not in use and seems really ugly!
233
+ */
234
+ VALUE Utils_normalize_host(int argc, VALUE *argv, VALUE self)
235
+ {
236
+ TRACE();
237
+ VALUE host, ip_type;
238
+ int force_pure_ipv6 = 0;
239
+
240
+ if (argc == 0 || argc > 3)
241
+ rb_raise(rb_eTypeError, "Wrong number of arguments (pass one, two or three)");
242
+
243
+ host = argv[0];
244
+ if (TYPE(host) != T_STRING)
245
+ rb_raise(rb_eTypeError, "First argument must be a String");
246
+
247
+ ip_type = argv[1];
248
+ if (TYPE(ip_type) != T_SYMBOL)
249
+ rb_raise(rb_eTypeError, "Second argument must be a Symbol (:ipv4, :ipv6 or :domain)");
250
+
251
+ if (argc == 3 && TYPE(argv[2]) != T_NIL && TYPE(argv[2]) != T_FALSE)
252
+ force_pure_ipv6 = 1;
253
+
254
+ if (ip_type == symbol_ipv6 || ip_type == symbol_ipv6_reference)
255
+ return utils_normalize_ipv6(host, force_pure_ipv6);
256
+ else
257
+ return host;
258
+ }
259
+
260
+
261
+ /*
262
+ * If the given argument is a IPV6 reference it returns a new string with the pure IPv6.
263
+ * In any other case, return the given argument.
264
+ *
265
+ * TODO: Not documented in the API (seems ugly).
266
+ */
267
+ VALUE Utils_to_pure_ip(VALUE self, VALUE string)
268
+ {
269
+ TRACE();
270
+ char *str;
271
+
272
+ str = StringValueCStr(string);
273
+ if (str[0] == '[')
274
+ return rb_str_new(RSTRING_PTR(string)+1, RSTRING_LEN(string)-2);
275
+ else
276
+ return string;
277
+ }
278
+
279
+
280
+ /*
281
+ * TODO: We lack a simple "normalice_host(ip)" method that parses the given ip and so on...
282
+ */
283
+
284
+
285
+ /*
286
+ * Expects a string like "1.2.3.4_5060" or "1af:43::ab_9090" and returns
287
+ * an Array as follows:
288
+ * [ ip_type, ip, port ]
289
+ * where:
290
+ * - ip_type is :ipv4 or :ipv6,
291
+ * - ip is a String,
292
+ * - port is a Fixnum
293
+ * If the string is invalid it returns false.
294
+ */
295
+ VALUE Utils_parser_outbound_udp_flow_token(VALUE self, VALUE string)
296
+ {
297
+ TRACE();
298
+ char *str = NULL;
299
+ long len = 0;
300
+ struct_outbound_udp_flow_token outbound_udp_flow_token;
301
+ VALUE ip_type, ip, port;
302
+
303
+ if (TYPE(string) != T_STRING)
304
+ rb_raise(rb_eTypeError, "Argument must be a String");
305
+
306
+ str = RSTRING_PTR(string);
307
+ len = RSTRING_LEN(string);
308
+
309
+ outbound_udp_flow_token = outbound_udp_flow_token_parser_execute(str, len);
310
+
311
+ if (outbound_udp_flow_token.valid == 0)
312
+ return Qfalse;
313
+ else {
314
+ if (outbound_udp_flow_token.ip_type == outbound_udp_flow_token_ip_type_ipv4)
315
+ ip_type = symbol_ipv4;
316
+ else
317
+ ip_type = symbol_ipv6;
318
+
319
+ ip = rb_str_new((char *)outbound_udp_flow_token.ip_s, outbound_udp_flow_token.ip_len);
320
+ port = INT2FIX(str_to_int((char *)outbound_udp_flow_token.port_s, outbound_udp_flow_token.port_len));
321
+
322
+ return rb_ary_new3(3, ip_type, ip, port);
323
+ }
324
+ }
325
+
326
+
327
+ /*
328
+ * Expects a string like "PROXY TCP4 192.168.0.1 192.168.0.11 56324 443\r\n" and returns
329
+ * an Array as follows:
330
+ * [ num_bytes, ip_type, ip, port ]
331
+ * where:
332
+ * - num_bytes is the length of the HAProxy Protocol line (to be removed), a Fixnum.
333
+ * - ip_type is :ipv4 or :ipv6,
334
+ * - ip is a String,
335
+ * - port is a Fixnum
336
+ * If the string is invalid it returns false.
337
+ */
338
+ VALUE Utils_parser_haproxy_protocol(VALUE self, VALUE string)
339
+ {
340
+ TRACE();
341
+ char *str = NULL;
342
+ long len = 0;
343
+ struct_haproxy_protocol haproxy_protocol;
344
+ VALUE num_bytes, ip_type, ip, port;
345
+
346
+ if (TYPE(string) != T_STRING)
347
+ rb_raise(rb_eTypeError, "Argument must be a String");
348
+
349
+ str = RSTRING_PTR(string);
350
+ len = RSTRING_LEN(string);
351
+
352
+ haproxy_protocol = struct_haproxy_protocol_parser_execute(str, len);
353
+
354
+ if (haproxy_protocol.valid == 0)
355
+ return Qfalse;
356
+ else {
357
+ if (haproxy_protocol.ip_type == haproxy_protocol_ip_type_ipv4)
358
+ ip_type = symbol_ipv4;
359
+ else
360
+ ip_type = symbol_ipv6;
361
+
362
+ ip = rb_str_new((char *)haproxy_protocol.ip_s, haproxy_protocol.ip_len);
363
+ port = INT2FIX(str_to_int((char *)haproxy_protocol.port_s, haproxy_protocol.port_len));
364
+ num_bytes = INT2FIX(haproxy_protocol.total_len);
365
+
366
+ return rb_ary_new3(4, num_bytes, ip_type, ip, port);
367
+ }
368
+ }
369
+
370
+
371
+ void Init_utils()
372
+ {
373
+ TRACE();
374
+
375
+ mOverSIP = rb_define_module("OverSIP");
376
+ mUtils = rb_define_module_under(mOverSIP, "Utils");
377
+
378
+ rb_define_module_function(mUtils, "ip?", Utils_is_ip, 1);
379
+ rb_define_module_function(mUtils, "pure_ip?", Utils_is_pure_ip, 1);
380
+ rb_define_module_function(mUtils, "ip_type", Utils_ip_type, 1);
381
+ rb_define_module_function(mUtils, "compare_ips", Utils_compare_ips, 2);
382
+ rb_define_module_function(mUtils, "compare_pure_ips", Utils_compare_pure_ips, 2);
383
+ rb_define_module_function(mUtils, "normalize_ipv6", Utils_normalize_ipv6, -1);
384
+ rb_define_module_function(mUtils, "normalize_host", Utils_normalize_host, -1);
385
+ rb_define_module_function(mUtils, "to_pure_ip", Utils_to_pure_ip, 1);
386
+ rb_define_module_function(mUtils, "parse_outbound_udp_flow_token", Utils_parser_outbound_udp_flow_token, 1);
387
+ rb_define_module_function(mUtils, "parse_haproxy_protocol", Utils_parser_haproxy_protocol, 1);
388
+
389
+ symbol_ipv4 = ID2SYM(rb_intern("ipv4"));
390
+ symbol_ipv6 = ID2SYM(rb_intern("ipv6"));
391
+ symbol_ipv6_reference = ID2SYM(rb_intern("ipv6_reference"));
392
+ }
@@ -0,0 +1,76 @@
1
+ /*
2
+ * This file is not used by Ruby OverSIP::Utils module itself, its aim is to
3
+ * be included by other OverSIP Ruby C extensions.
4
+ */
5
+
6
+ #ifndef utils_ruby_h
7
+ #define utils_ruby_h
8
+
9
+
10
+ #include "ip_utils.h"
11
+ #include "outbound_utils.h"
12
+ #include "haproxy_protocol.h"
13
+ #include <arpa/inet.h> // inet_ntop()
14
+
15
+
16
+ /* Export the Ruby C functions so other C libraries within OverSIP can use them. */
17
+ VALUE Utils_is_ip(VALUE self, VALUE string);
18
+ VALUE Utils_is_pure_ip(VALUE self, VALUE string);
19
+ VALUE Utils_ip_type(VALUE self, VALUE string);
20
+ VALUE Utils_compare_ips(VALUE self, VALUE string1, VALUE string2);
21
+ VALUE Utils_compare_pure_ips(VALUE self, VALUE string1, VALUE string2);
22
+ VALUE Utils_normalize_ipv6(int argc, VALUE *argv, VALUE self);
23
+ VALUE Utils_normalize_host(int argc, VALUE *argv, VALUE self);
24
+ VALUE Utils_to_pure_ip(VALUE self, VALUE string);
25
+ VALUE Utils_parser_outbound_udp_flow_token(VALUE self, VALUE string);
26
+ VALUE Utils_parser_haproxy_protocol(VALUE self, VALUE string);
27
+
28
+
29
+ VALUE utils_normalize_ipv6(VALUE string, int force_pure_ipv6)
30
+ {
31
+ struct in6_addr addr;
32
+ char normalized_ipv6[INET6_ADDRSTRLEN + 1];
33
+ char normalized_ipv6_reference[INET6_ADDRSTRLEN + 3];
34
+ char *str, str2[INET6_ADDRSTRLEN + 3], *str_pointer;
35
+ int is_ipv6_reference = 0;
36
+
37
+ str = StringValueCStr(string);
38
+ if (str[0] != '[') {
39
+ str_pointer = str;
40
+ }
41
+ else {
42
+ is_ipv6_reference = 1;
43
+ memcpy(str2, str + 1, strlen(str) - 2);
44
+ str2[strlen(str) - 2] = '\0';
45
+ str_pointer = str2;
46
+ }
47
+
48
+ switch(inet_pton(AF_INET6, str_pointer, &addr)) {
49
+ /* Not a valid IPv6. */
50
+ case 0:
51
+ return Qfalse;
52
+ break;
53
+ /* Some error ocurred. */
54
+ case -1:
55
+ return Qnil;
56
+ break;
57
+ default:
58
+ break;
59
+ }
60
+
61
+ if (inet_ntop(AF_INET6, &addr, normalized_ipv6, INET6_ADDRSTRLEN))
62
+ if (is_ipv6_reference && !force_pure_ipv6) {
63
+ memcpy(normalized_ipv6_reference, "[", 1);
64
+ memcpy(normalized_ipv6_reference + 1, normalized_ipv6, strlen(normalized_ipv6));
65
+ memcpy(normalized_ipv6_reference + strlen(normalized_ipv6) + 1, "]\0", 2);
66
+ return rb_str_new_cstr(normalized_ipv6_reference);
67
+ }
68
+ else
69
+ return rb_str_new_cstr(normalized_ipv6);
70
+ /* Some error ocurred. */
71
+ else
72
+ return Qnil;
73
+ }
74
+
75
+
76
+ #endif
@@ -0,0 +1,18 @@
1
+ #ifndef ext_help_h
2
+ #define ext_help_h
3
+
4
+ #define RAISE_NOT_NULL(T) if(T == NULL) rb_raise(rb_eArgError, "NULL found for " # T " when shouldn't be.");
5
+ #define DATA_GET(from,type,name) Data_Get_Struct(from,type,name); RAISE_NOT_NULL(name);
6
+ #define REQUIRE_TYPE(V, T) if(TYPE(V) != T) rb_raise(rb_eTypeError, "Wrong argument type for " # V " required " # T);
7
+
8
+
9
+ /* Uncomment for enabling TRACE() function. */
10
+ /*#define DEBUG*/
11
+
12
+ #ifdef DEBUG
13
+ #define TRACE() fprintf(stderr, "TRACE: %s:%d:%s\n", __FILE__, __LINE__, __FUNCTION__)
14
+ #else
15
+ #define TRACE()
16
+ #endif
17
+
18
+ #endif
@@ -0,0 +1,3 @@
1
+ require "mkmf"
2
+
3
+ create_makefile("oversip/websocket/ws_framing_utils")
@@ -0,0 +1,47 @@
1
+ #ifndef ws_framing_utils_h
2
+ #define ws_framing_utils_h
3
+
4
+
5
+ #include <stdint.h>
6
+
7
+
8
+ /* Extracted from http://bjoern.hoehrmann.de/utf-8/decoder/dfa/ */
9
+
10
+ #define UTF8_ACCEPT 0
11
+ #define UTF8_REJECT 1
12
+ #define UTF8D_SIZE 400
13
+
14
+ static const uint8_t utf8d[] = {
15
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 00..1f */
16
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 20..3f */
17
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 40..5f */
18
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 60..7f */
19
+ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, /* 80..9f */
20
+ 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, /* a0..bf */
21
+ 8,8,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, /* c0..df */
22
+ 0xa,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x4,0x3,0x3, /* e0..ef */
23
+ 0xb,0x6,0x6,0x6,0x5,0x8,0x8,0x8,0x8,0x8,0x8,0x8,0x8,0x8,0x8,0x8, /* f0..ff */
24
+ 0x0,0x1,0x2,0x3,0x5,0x8,0x7,0x1,0x1,0x1,0x4,0x6,0x1,0x1,0x1,0x1, /* s0..s0 */
25
+ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,0,1,0,1,1,1,1,1,1, /* s1..s2 */
26
+ 1,2,1,1,1,1,1,2,1,2,1,1,1,1,1,1,1,1,1,1,1,1,1,2,1,1,1,1,1,1,1,1, /* s3..s4 */
27
+ 1,2,1,1,1,1,1,1,1,2,1,1,1,1,1,1,1,1,1,1,1,1,1,3,1,3,1,1,1,1,1,1, /* s5..s6 */
28
+ 1,3,1,1,1,1,1,3,1,3,1,1,1,1,1,1,1,3,1,1,1,1,1,1,1,1,1,1,1,1,1,1 /* s7..s8 */
29
+ };
30
+
31
+ static inline
32
+ uint32_t utf8_decode(uint32_t* state, uint32_t* codep, uint32_t byte) {
33
+ uint32_t type = utf8d[byte];
34
+
35
+ *codep = (*state != UTF8_ACCEPT) ? (byte & 0x3fu) | (*codep << 6) : (0xff >> type) & (byte);
36
+ *state = utf8d[256 + *state*16 + type];
37
+ return *state;
38
+ }
39
+
40
+
41
+ typedef struct utf8_validator {
42
+ uint32_t codepoint;
43
+ uint32_t state;
44
+ } utf8_validator;
45
+
46
+
47
+ #endif
@@ -0,0 +1,135 @@
1
+ #include <ruby.h>
2
+ #include "ws_framing_utils.h"
3
+ #include "ext_help.h"
4
+
5
+
6
+ static VALUE mOverSIP;
7
+ static VALUE mWebSocket;
8
+ static VALUE mFramingUtils;
9
+ static VALUE cUtf8Validator;
10
+
11
+
12
+
13
+ /*
14
+ * Ruby functions.
15
+ */
16
+
17
+ VALUE WsFramingUtils_unmask(VALUE self, VALUE payload, VALUE mask)
18
+ {
19
+ char *payload_str, *mask_str;
20
+ long payload_len; /* mask length is always 4 bytes. */
21
+ char *unmasked_payload_str;
22
+ VALUE rb_unmasked_payload;
23
+ int i;
24
+
25
+ if (TYPE(payload) != T_STRING)
26
+ rb_raise(rb_eTypeError, "Argument must be a String");
27
+
28
+ if (TYPE(mask) != T_STRING)
29
+ rb_raise(rb_eTypeError, "Argument must be a String");
30
+
31
+ if (RSTRING_LEN(mask) != 4)
32
+ rb_raise(rb_eTypeError, "mask size must be 4 bytes");
33
+
34
+ payload_str = RSTRING_PTR(payload);
35
+ payload_len = RSTRING_LEN(payload);
36
+ mask_str = RSTRING_PTR(mask);
37
+
38
+ /* NOTE: In Ruby C extensions always use:
39
+ * pointer = ALLOC_N(type, n)
40
+ * which means: pointer = (type*)xmalloc(sizeof(type)*(n))
41
+ * and:
42
+ * xfree()
43
+ */
44
+
45
+ unmasked_payload_str = ALLOC_N(char, payload_len);
46
+
47
+ for(i=0; i < payload_len; i++)
48
+ unmasked_payload_str[i] = payload_str[i] ^ mask_str[i % 4];
49
+
50
+ rb_unmasked_payload = rb_str_new(unmasked_payload_str, payload_len);
51
+ xfree(unmasked_payload_str);
52
+ return(rb_unmasked_payload);
53
+ }
54
+
55
+
56
+ static void Utf8Validator_free(void *validator)
57
+ {
58
+ TRACE();
59
+ if(validator) {
60
+ xfree(validator);
61
+ }
62
+ }
63
+
64
+
65
+ VALUE Utf8Validator_alloc(VALUE klass)
66
+ {
67
+ TRACE();
68
+ VALUE obj;
69
+ utf8_validator *validator = ALLOC(utf8_validator);
70
+
71
+ validator->state = UTF8_ACCEPT;
72
+
73
+ obj = Data_Wrap_Struct(klass, NULL, Utf8Validator_free, validator);
74
+ return obj;
75
+ }
76
+
77
+
78
+ VALUE Utf8Validator_reset(VALUE self)
79
+ {
80
+ TRACE();
81
+ utf8_validator *validator = NULL;
82
+ DATA_GET(self, utf8_validator, validator);
83
+
84
+ validator->state = UTF8_ACCEPT;
85
+
86
+ return Qnil;
87
+ }
88
+
89
+
90
+ /*
91
+ * Returns:
92
+ * - true: Valid UTF-8 string.
93
+ * - nil: Valid but not terminated UTF-8 string.
94
+ * - false: Invalid UTF-8 string.
95
+ */
96
+ VALUE Utf8Validator_validate(VALUE self, VALUE string)
97
+ {
98
+ TRACE();
99
+ utf8_validator *validator = NULL;
100
+ uint8_t *str = NULL;
101
+ int i;
102
+
103
+ REQUIRE_TYPE(string, T_STRING);
104
+ str = (uint8_t *)RSTRING_PTR(string);
105
+
106
+ DATA_GET(self, utf8_validator, validator);
107
+
108
+ for(i=0; i < RSTRING_LEN(string); i++)
109
+ if (utf8_decode(&validator->state, &validator->codepoint, str[i]) == UTF8_REJECT)
110
+ return Qfalse;
111
+
112
+ switch(validator->state) {
113
+ case UTF8_ACCEPT:
114
+ return Qtrue;
115
+ break;
116
+ default:
117
+ return Qnil;
118
+ break;
119
+ }
120
+ }
121
+
122
+
123
+ void Init_ws_framing_utils()
124
+ {
125
+ mOverSIP = rb_define_module("OverSIP");
126
+ mWebSocket = rb_define_module_under(mOverSIP, "WebSocket");
127
+ mFramingUtils = rb_define_module_under(mWebSocket, "FramingUtils");
128
+ cUtf8Validator = rb_define_class_under(mFramingUtils, "Utf8Validator", rb_cObject);
129
+
130
+ rb_define_module_function(mFramingUtils, "unmask", WsFramingUtils_unmask,2);
131
+
132
+ rb_define_alloc_func(cUtf8Validator, Utf8Validator_alloc);
133
+ rb_define_method(cUtf8Validator, "reset", Utf8Validator_reset,0);
134
+ rb_define_method(cUtf8Validator, "validate", Utf8Validator_validate,1);
135
+ }