oversip 0.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/AUTHORS.txt +11 -0
- data/LICENSE.txt +22 -0
- data/README.md +16 -0
- data/Rakefile +55 -0
- data/bin/oversip +182 -0
- data/ext/common/c_util.h +74 -0
- data/ext/common/ruby_c_util.h +88 -0
- data/ext/sip_parser/common_headers.h +209 -0
- data/ext/sip_parser/ext_help.h +18 -0
- data/ext/sip_parser/extconf.rb +3 -0
- data/ext/sip_parser/sip_parser.c +29649 -0
- data/ext/sip_parser/sip_parser.h +227 -0
- data/ext/sip_parser/sip_parser_ruby.c +1292 -0
- data/ext/stud/extconf.rb +27 -0
- data/ext/stud/stud.tar.gz +0 -0
- data/ext/stun/ext_help.h +16 -0
- data/ext/stun/extconf.rb +3 -0
- data/ext/stun/stun_ruby.c +391 -0
- data/ext/utils/ext_help.h +14 -0
- data/ext/utils/extconf.rb +3 -0
- data/ext/utils/haproxy_protocol.c +6163 -0
- data/ext/utils/haproxy_protocol.h +27 -0
- data/ext/utils/ip_utils.c +5952 -0
- data/ext/utils/ip_utils.h +61 -0
- data/ext/utils/outbound_utils.c +3227 -0
- data/ext/utils/outbound_utils.h +27 -0
- data/ext/utils/utils_ruby.c +384 -0
- data/ext/utils/utils_ruby.h +75 -0
- data/ext/websocket_framing_utils/ext_help.h +18 -0
- data/ext/websocket_framing_utils/extconf.rb +3 -0
- data/ext/websocket_framing_utils/ws_framing_utils.h +46 -0
- data/ext/websocket_framing_utils/ws_framing_utils_ruby.c +135 -0
- data/ext/websocket_http_parser/ext_help.h +18 -0
- data/ext/websocket_http_parser/extconf.rb +3 -0
- data/ext/websocket_http_parser/ws_http_parser.c +2598 -0
- data/ext/websocket_http_parser/ws_http_parser.h +86 -0
- data/ext/websocket_http_parser/ws_http_parser_ruby.c +630 -0
- data/lib/oversip/config.rb +541 -0
- data/lib/oversip/config_validators.rb +126 -0
- data/lib/oversip/errors.rb +7 -0
- data/lib/oversip/fiber_pool.rb +56 -0
- data/lib/oversip/launcher.rb +507 -0
- data/lib/oversip/logger.rb +170 -0
- data/lib/oversip/master_process.rb +67 -0
- data/lib/oversip/posix_mq.rb +121 -0
- data/lib/oversip/proxies_config.rb +169 -0
- data/lib/oversip/ruby_ext/eventmachine.rb +38 -0
- data/lib/oversip/sip/client_transaction.rb +587 -0
- data/lib/oversip/sip/constants.rb +87 -0
- data/lib/oversip/sip/grammar/name_addr.rb +27 -0
- data/lib/oversip/sip/grammar/uri.rb +116 -0
- data/lib/oversip/sip/launcher.rb +180 -0
- data/lib/oversip/sip/listeners/ipv4_tcp_client.rb +21 -0
- data/lib/oversip/sip/listeners/ipv4_tcp_server.rb +21 -0
- data/lib/oversip/sip/listeners/ipv4_tls_client.rb +21 -0
- data/lib/oversip/sip/listeners/ipv4_tls_server.rb +21 -0
- data/lib/oversip/sip/listeners/ipv4_tls_tunnel_server.rb +21 -0
- data/lib/oversip/sip/listeners/ipv4_udp_server.rb +20 -0
- data/lib/oversip/sip/listeners/ipv6_tcp_client.rb +21 -0
- data/lib/oversip/sip/listeners/ipv6_tcp_server.rb +21 -0
- data/lib/oversip/sip/listeners/ipv6_tls_client.rb +21 -0
- data/lib/oversip/sip/listeners/ipv6_tls_server.rb +21 -0
- data/lib/oversip/sip/listeners/ipv6_tls_tunnel_server.rb +21 -0
- data/lib/oversip/sip/listeners/ipv6_udp_server.rb +20 -0
- data/lib/oversip/sip/listeners/reactor.rb +39 -0
- data/lib/oversip/sip/listeners/tcp_client.rb +73 -0
- data/lib/oversip/sip/listeners/tcp_reactor.rb +185 -0
- data/lib/oversip/sip/listeners/tcp_server.rb +71 -0
- data/lib/oversip/sip/listeners/tls_client.rb +117 -0
- data/lib/oversip/sip/listeners/tls_server.rb +70 -0
- data/lib/oversip/sip/listeners/tls_tunnel_reactor.rb +113 -0
- data/lib/oversip/sip/listeners/tls_tunnel_server.rb +61 -0
- data/lib/oversip/sip/listeners/udp_reactor.rb +213 -0
- data/lib/oversip/sip/listeners.rb +28 -0
- data/lib/oversip/sip/logic.rb +14 -0
- data/lib/oversip/sip/message.rb +168 -0
- data/lib/oversip/sip/message_processor.rb +202 -0
- data/lib/oversip/sip/modules/core.rb +200 -0
- data/lib/oversip/sip/modules/registrar_without_path.rb +75 -0
- data/lib/oversip/sip/modules/user_assertion.rb +123 -0
- data/lib/oversip/sip/proxy.rb +460 -0
- data/lib/oversip/sip/request.rb +128 -0
- data/lib/oversip/sip/response.rb +30 -0
- data/lib/oversip/sip/rfc3263.rb +646 -0
- data/lib/oversip/sip/server_transaction.rb +295 -0
- data/lib/oversip/sip/sip.rb +74 -0
- data/lib/oversip/sip/tags.rb +39 -0
- data/lib/oversip/sip/timers.rb +55 -0
- data/lib/oversip/sip/transport_manager.rb +129 -0
- data/lib/oversip/syslogger_process.rb +119 -0
- data/lib/oversip/tls.rb +179 -0
- data/lib/oversip/utils.rb +25 -0
- data/lib/oversip/version.rb +23 -0
- data/lib/oversip/websocket/constants.rb +56 -0
- data/lib/oversip/websocket/default_policy.rb +19 -0
- data/lib/oversip/websocket/http_request.rb +63 -0
- data/lib/oversip/websocket/launcher.rb +207 -0
- data/lib/oversip/websocket/listeners/ipv4_tcp_server.rb +15 -0
- data/lib/oversip/websocket/listeners/ipv4_tls_server.rb +15 -0
- data/lib/oversip/websocket/listeners/ipv4_tls_tunnel_server.rb +15 -0
- data/lib/oversip/websocket/listeners/ipv6_tcp_server.rb +15 -0
- data/lib/oversip/websocket/listeners/ipv6_tls_server.rb +15 -0
- data/lib/oversip/websocket/listeners/ipv6_tls_tunnel_server.rb +15 -0
- data/lib/oversip/websocket/listeners/tcp_server.rb +265 -0
- data/lib/oversip/websocket/listeners/tls_server.rb +69 -0
- data/lib/oversip/websocket/listeners/tls_tunnel_server.rb +100 -0
- data/lib/oversip/websocket/listeners.rb +12 -0
- data/lib/oversip/websocket/ws_app.rb +75 -0
- data/lib/oversip/websocket/ws_apps/ipv4_ws_sip_app.rb +21 -0
- data/lib/oversip/websocket/ws_apps/ipv4_wss_sip_app.rb +21 -0
- data/lib/oversip/websocket/ws_apps/ipv6_ws_sip_app.rb +21 -0
- data/lib/oversip/websocket/ws_apps/ipv6_wss_sip_app.rb +22 -0
- data/lib/oversip/websocket/ws_apps/ws_autobahn_app.rb +23 -0
- data/lib/oversip/websocket/ws_apps/ws_sip_app.rb +156 -0
- data/lib/oversip/websocket/ws_apps.rb +9 -0
- data/lib/oversip/websocket/ws_framing.rb +597 -0
- data/lib/oversip.rb +59 -0
- data/test/oversip_test_helper.rb +20 -0
- data/test/test_http_parser.rb +73 -0
- data/test/test_sip_parser.rb +139 -0
- metadata +256 -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,384 @@
|
|
|
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
|
+
VALUE Utils_normalize_host(int argc, VALUE *argv, VALUE self)
|
|
233
|
+
{
|
|
234
|
+
TRACE();
|
|
235
|
+
VALUE host, ip_type;
|
|
236
|
+
int force_pure_ipv6 = 0;
|
|
237
|
+
|
|
238
|
+
if (argc == 0 || argc > 3)
|
|
239
|
+
rb_raise(rb_eTypeError, "Wrong number of arguments (pass one, two or three)");
|
|
240
|
+
|
|
241
|
+
host = argv[0];
|
|
242
|
+
if (TYPE(host) != T_STRING)
|
|
243
|
+
rb_raise(rb_eTypeError, "First argument must be a String");
|
|
244
|
+
|
|
245
|
+
ip_type = argv[1];
|
|
246
|
+
if (TYPE(ip_type) != T_SYMBOL)
|
|
247
|
+
rb_raise(rb_eTypeError, "Second argument must be a Symbol (:ipv4, :ipv6 or :domain)");
|
|
248
|
+
|
|
249
|
+
if (argc == 3 && TYPE(argv[2]) != T_NIL && TYPE(argv[2]) != T_FALSE)
|
|
250
|
+
force_pure_ipv6 = 1;
|
|
251
|
+
|
|
252
|
+
if (ip_type == symbol_ipv6 || ip_type == symbol_ipv6_reference)
|
|
253
|
+
return utils_normalize_ipv6(host, force_pure_ipv6);
|
|
254
|
+
else
|
|
255
|
+
return host;
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
|
|
259
|
+
/*
|
|
260
|
+
* If the given argument is a IPV6 reference it returns a new string with the pure IPv6.
|
|
261
|
+
* In any other case, return the given argument.
|
|
262
|
+
*/
|
|
263
|
+
VALUE Utils_to_pure_ip(VALUE self, VALUE string)
|
|
264
|
+
{
|
|
265
|
+
TRACE();
|
|
266
|
+
char *str;
|
|
267
|
+
|
|
268
|
+
str = StringValueCStr(string);
|
|
269
|
+
if (str[0] == '[')
|
|
270
|
+
return rb_str_new(RSTRING_PTR(string)+1, RSTRING_LEN(string)-2);
|
|
271
|
+
else
|
|
272
|
+
return string;
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
|
|
276
|
+
/*
|
|
277
|
+
* Expects a string like "1.2.3.4_5060" or "1af:43::ab_9090" and returns
|
|
278
|
+
* an Array as follows:
|
|
279
|
+
* [ ip_type, ip, port ]
|
|
280
|
+
* where:
|
|
281
|
+
* - ip_type is :ipv4 or :ipv6,
|
|
282
|
+
* - ip is a String,
|
|
283
|
+
* - port is a Fixnum
|
|
284
|
+
* If the string is invalid it returns false.
|
|
285
|
+
*/
|
|
286
|
+
VALUE Utils_parser_outbound_udp_flow_token(VALUE self, VALUE string)
|
|
287
|
+
{
|
|
288
|
+
TRACE();
|
|
289
|
+
char *str = NULL;
|
|
290
|
+
long len = 0;
|
|
291
|
+
struct_outbound_udp_flow_token outbound_udp_flow_token;
|
|
292
|
+
VALUE ip_type, ip, port;
|
|
293
|
+
|
|
294
|
+
if (TYPE(string) != T_STRING)
|
|
295
|
+
rb_raise(rb_eTypeError, "Argument must be a String");
|
|
296
|
+
|
|
297
|
+
str = RSTRING_PTR(string);
|
|
298
|
+
len = RSTRING_LEN(string);
|
|
299
|
+
|
|
300
|
+
/* Remove the leading "_" from the string. */
|
|
301
|
+
outbound_udp_flow_token = outbound_udp_flow_token_parser_execute(str, len);
|
|
302
|
+
|
|
303
|
+
if (outbound_udp_flow_token.valid == 0)
|
|
304
|
+
return Qfalse;
|
|
305
|
+
else {
|
|
306
|
+
if (outbound_udp_flow_token.ip_type == outbound_udp_flow_token_ip_type_ipv4)
|
|
307
|
+
ip_type = symbol_ipv4;
|
|
308
|
+
else
|
|
309
|
+
ip_type = symbol_ipv6;
|
|
310
|
+
|
|
311
|
+
ip = rb_str_new((char *)outbound_udp_flow_token.ip_s, outbound_udp_flow_token.ip_len);
|
|
312
|
+
port = INT2FIX(str_to_int((char *)outbound_udp_flow_token.port_s, outbound_udp_flow_token.port_len));
|
|
313
|
+
|
|
314
|
+
return rb_ary_new3(3, ip_type, ip, port);
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
|
|
319
|
+
/*
|
|
320
|
+
* Expects a string like "PROXY TCP4 192.168.0.1 192.168.0.11 56324 443\r\n" and returns
|
|
321
|
+
* an Array as follows:
|
|
322
|
+
* [ num_bytes, ip_type, ip, port ]
|
|
323
|
+
* where:
|
|
324
|
+
* - num_bytes is the length of the HAProxy Protocol line (to be removed), a Fixnum.
|
|
325
|
+
* - ip_type is :ipv4 or :ipv6,
|
|
326
|
+
* - ip is a String,
|
|
327
|
+
* - port is a Fixnum
|
|
328
|
+
* If the string is invalid it returns false.
|
|
329
|
+
*/
|
|
330
|
+
VALUE Utils_parser_haproxy_protocol(VALUE self, VALUE string)
|
|
331
|
+
{
|
|
332
|
+
TRACE();
|
|
333
|
+
char *str = NULL;
|
|
334
|
+
long len = 0;
|
|
335
|
+
struct_haproxy_protocol haproxy_protocol;
|
|
336
|
+
VALUE num_bytes, ip_type, ip, port;
|
|
337
|
+
|
|
338
|
+
if (TYPE(string) != T_STRING)
|
|
339
|
+
rb_raise(rb_eTypeError, "Argument must be a String");
|
|
340
|
+
|
|
341
|
+
str = RSTRING_PTR(string);
|
|
342
|
+
len = RSTRING_LEN(string);
|
|
343
|
+
|
|
344
|
+
haproxy_protocol = struct_haproxy_protocol_parser_execute(str, len);
|
|
345
|
+
|
|
346
|
+
if (haproxy_protocol.valid == 0)
|
|
347
|
+
return Qfalse;
|
|
348
|
+
else {
|
|
349
|
+
if (haproxy_protocol.ip_type == haproxy_protocol_ip_type_ipv4)
|
|
350
|
+
ip_type = symbol_ipv4;
|
|
351
|
+
else
|
|
352
|
+
ip_type = symbol_ipv6;
|
|
353
|
+
|
|
354
|
+
ip = rb_str_new((char *)haproxy_protocol.ip_s, haproxy_protocol.ip_len);
|
|
355
|
+
port = INT2FIX(str_to_int((char *)haproxy_protocol.port_s, haproxy_protocol.port_len));
|
|
356
|
+
num_bytes = INT2FIX(haproxy_protocol.total_len);
|
|
357
|
+
|
|
358
|
+
return rb_ary_new3(4, num_bytes, ip_type, ip, port);
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
|
|
363
|
+
void Init_utils()
|
|
364
|
+
{
|
|
365
|
+
TRACE();
|
|
366
|
+
|
|
367
|
+
mOverSIP = rb_define_module("OverSIP");
|
|
368
|
+
mUtils = rb_define_module_under(mOverSIP, "Utils");
|
|
369
|
+
|
|
370
|
+
rb_define_module_function(mUtils, "ip?", Utils_is_ip, 1);
|
|
371
|
+
rb_define_module_function(mUtils, "pure_ip?", Utils_is_pure_ip, 1);
|
|
372
|
+
rb_define_module_function(mUtils, "ip_type", Utils_ip_type, 1);
|
|
373
|
+
rb_define_module_function(mUtils, "compare_ips", Utils_compare_ips, 2);
|
|
374
|
+
rb_define_module_function(mUtils, "compare_pure_ips", Utils_compare_pure_ips, 2);
|
|
375
|
+
rb_define_module_function(mUtils, "normalize_ipv6", Utils_normalize_ipv6, -1);
|
|
376
|
+
rb_define_module_function(mUtils, "normalize_host", Utils_normalize_host, -1);
|
|
377
|
+
rb_define_module_function(mUtils, "to_pure_ip", Utils_to_pure_ip, 1);
|
|
378
|
+
rb_define_module_function(mUtils, "parse_outbound_udp_flow_token", Utils_parser_outbound_udp_flow_token, 1);
|
|
379
|
+
rb_define_module_function(mUtils, "parse_haproxy_protocol", Utils_parser_haproxy_protocol, 1);
|
|
380
|
+
|
|
381
|
+
symbol_ipv4 = ID2SYM(rb_intern("ipv4"));
|
|
382
|
+
symbol_ipv6 = ID2SYM(rb_intern("ipv6"));
|
|
383
|
+
symbol_ipv6_reference = ID2SYM(rb_intern("ipv6_reference"));
|
|
384
|
+
}
|
|
@@ -0,0 +1,75 @@
|
|
|
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
|
+
|
|
14
|
+
|
|
15
|
+
/* Export the Ruby C functions so other C libraries within OverSIP can use them. */
|
|
16
|
+
VALUE Utils_is_ip(VALUE self, VALUE string);
|
|
17
|
+
VALUE Utils_is_pure_ip(VALUE self, VALUE string);
|
|
18
|
+
VALUE Utils_ip_type(VALUE self, VALUE string);
|
|
19
|
+
VALUE Utils_compare_ips(VALUE self, VALUE string1, VALUE string2);
|
|
20
|
+
VALUE Utils_compare_pure_ips(VALUE self, VALUE string1, VALUE string2);
|
|
21
|
+
VALUE Utils_normalize_ipv6(int argc, VALUE *argv, VALUE self);
|
|
22
|
+
VALUE Utils_normalize_host(int argc, VALUE *argv, VALUE self);
|
|
23
|
+
VALUE Utils_to_pure_ip(VALUE self, VALUE string);
|
|
24
|
+
VALUE Utils_parser_outbound_udp_flow_token(VALUE self, VALUE string);
|
|
25
|
+
VALUE Utils_parser_haproxy_protocol(VALUE self, VALUE string);
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
VALUE utils_normalize_ipv6(VALUE string, int force_pure_ipv6)
|
|
29
|
+
{
|
|
30
|
+
struct in6_addr addr;
|
|
31
|
+
char normalized_ipv6[INET6_ADDRSTRLEN + 1];
|
|
32
|
+
char normalized_ipv6_reference[INET6_ADDRSTRLEN + 3];
|
|
33
|
+
char *str, str2[INET6_ADDRSTRLEN + 3], *str_pointer;
|
|
34
|
+
int is_ipv6_reference = 0;
|
|
35
|
+
|
|
36
|
+
str = StringValueCStr(string);
|
|
37
|
+
if (str[0] != '[') {
|
|
38
|
+
str_pointer = str;
|
|
39
|
+
}
|
|
40
|
+
else {
|
|
41
|
+
is_ipv6_reference = 1;
|
|
42
|
+
memcpy(str2, str + 1, strlen(str) - 2);
|
|
43
|
+
str2[strlen(str) - 2] = '\0';
|
|
44
|
+
str_pointer = str2;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
switch(inet_pton(AF_INET6, str_pointer, &addr)) {
|
|
48
|
+
/* Not a valid IPv6. */
|
|
49
|
+
case 0:
|
|
50
|
+
return Qfalse;
|
|
51
|
+
break;
|
|
52
|
+
/* Some error ocurred. */
|
|
53
|
+
case -1:
|
|
54
|
+
return Qnil;
|
|
55
|
+
break;
|
|
56
|
+
default:
|
|
57
|
+
break;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
if (inet_ntop(AF_INET6, &addr, normalized_ipv6, INET6_ADDRSTRLEN))
|
|
61
|
+
if (is_ipv6_reference && !force_pure_ipv6) {
|
|
62
|
+
memcpy(normalized_ipv6_reference, "[", 1);
|
|
63
|
+
memcpy(normalized_ipv6_reference + 1, normalized_ipv6, strlen(normalized_ipv6));
|
|
64
|
+
memcpy(normalized_ipv6_reference + strlen(normalized_ipv6) + 1, "]\0", 2);
|
|
65
|
+
return rb_str_new_cstr(normalized_ipv6_reference);
|
|
66
|
+
}
|
|
67
|
+
else
|
|
68
|
+
return rb_str_new_cstr(normalized_ipv6);
|
|
69
|
+
/* Some error ocurred. */
|
|
70
|
+
else
|
|
71
|
+
return Qnil;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
#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,46 @@
|
|
|
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
|
+
uint32_t inline utf8_decode(uint32_t* state, uint32_t* codep, uint32_t byte) {
|
|
32
|
+
uint32_t type = utf8d[byte];
|
|
33
|
+
|
|
34
|
+
*codep = (*state != UTF8_ACCEPT) ? (byte & 0x3fu) | (*codep << 6) : (0xff >> type) & (byte);
|
|
35
|
+
*state = utf8d[256 + *state*16 + type];
|
|
36
|
+
return *state;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
typedef struct utf8_validator {
|
|
41
|
+
uint32_t codepoint;
|
|
42
|
+
uint32_t state;
|
|
43
|
+
} utf8_validator;
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
#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 WsFrammingUtils_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 = 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", WsFrammingUtils_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
|
+
}
|
|
@@ -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
|