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,43 @@
1
+ require "mkmf"
2
+ require "fileutils"
3
+ require "rbconfig"
4
+
5
+
6
+ def log(message)
7
+ puts "[ext/stud/extconf.rb] #{message}"
8
+ end
9
+
10
+
11
+ def sys(cmd)
12
+ log "executing system command: #{cmd}"
13
+ unless ret = xsystem(cmd)
14
+ raise "[ext/stud/extconf.rb] system command `#{cmd}' failed"
15
+ end
16
+ ret
17
+ end
18
+
19
+
20
+ here = File.expand_path(File.dirname(__FILE__))
21
+ stud_dir = "#{here}/../../thirdparty/stud/"
22
+ stud_tarball = "stud.tar.gz"
23
+
24
+ Dir.chdir(stud_dir) do
25
+ sys("tar -zxf #{stud_tarball}")
26
+
27
+ Dir.chdir("stud") do
28
+ host_os = RbConfig::CONFIG["host_os"]
29
+ log "RbConfig::CONFIG['host_os'] returns #{host_os.inspect}"
30
+ case host_os
31
+ when /bsd/i
32
+ log "BSD detected, using `gmake' instead of `make'"
33
+ sys("gmake")
34
+ else
35
+ sys("make")
36
+ end
37
+ FileUtils.mv "stud", "../../../bin/oversip_stud"
38
+ end
39
+
40
+ FileUtils.remove_dir("stud", force = true)
41
+ end
42
+
43
+ create_makefile("stud")
@@ -0,0 +1,16 @@
1
+ #ifndef ext_help_h
2
+ #define ext_help_h
3
+
4
+ /* Uncomment for enabling TRACE() function. */
5
+ /*#define DEBUG*/
6
+
7
+ #ifdef DEBUG
8
+ #define TRACE() fprintf(stderr, "TRACE: %s:%d:%s\n", __FILE__, __LINE__, __FUNCTION__)
9
+ #define LOG(string) fprintf(stderr, "LOG: %s:%d:%s: %s\n", __FILE__, __LINE__, __FUNCTION__, string)
10
+ #else
11
+ #define TRACE()
12
+ #define LOG(string)
13
+ #endif
14
+
15
+ #endif
16
+
@@ -0,0 +1,3 @@
1
+ require "mkmf"
2
+
3
+ create_makefile("oversip/stun")
@@ -0,0 +1,394 @@
1
+ #include <ruby.h>
2
+ #include <netinet/in.h>
3
+ #include <arpa/inet.h>
4
+ #include "ext_help.h"
5
+
6
+
7
+ #define STUN_MESSAGE_MIN_SIZE 20
8
+ #define STUN_MAGIC_COOKIE_LEN 4
9
+ #define STUN_TRANSACTION_ID_LEN 12
10
+ #define STUN_BINDING_SUCCESS_RESPONSE_IPV4_SIZE 32
11
+ #define STUN_BINDING_SUCCESS_RESPONSE_IPV6_SIZE 44
12
+
13
+
14
+ static VALUE mOverSIP;
15
+ static VALUE mStun;
16
+
17
+
18
+ /*
19
+ * Ruby functions.
20
+ */
21
+
22
+
23
+ /*
24
+ * RFC 5389.
25
+ *
26
+ * 6. STUN Message Structure
27
+ *
28
+ * 0 1 2 3
29
+ * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
30
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
31
+ * |0 0| STUN Message Type | Message Length |
32
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
33
+ * | Magic Cookie |
34
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
35
+ * | |
36
+ * | Transaction ID (96 bits) |
37
+ * | |
38
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
39
+ *
40
+ */
41
+
42
+
43
+ /*
44
+ * Expects 3 arguments:
45
+ * - String containing a STUN Binding Request (MUST not be empty!!).
46
+ * - String containing the source IP of the request.
47
+ * - Fxinum containing the source port of the request.
48
+ * Return value:
49
+ * - If it's a valid STUN Binding Request, returns a Ruby String representing the
50
+ * STUN Binding Response.
51
+ * - If it seems a valid STUN message but not a valid STUN Binding Request, returns _false_.
52
+ * - Otherwise returns _nil_ (so it could be a SIP message).
53
+ */
54
+ VALUE Stun_parse_request(VALUE self, VALUE rb_stun_request, VALUE rb_source_ip, VALUE rb_source_port)
55
+ {
56
+ TRACE();
57
+
58
+ char *request = NULL;
59
+ size_t request_len = 0;
60
+ char *source_ip = NULL;
61
+ short source_ip_is_ipv6 = 0;
62
+ uint16_t source_port;
63
+
64
+ char *transaction_id;
65
+ uint16_t message_length;
66
+ char *magic_cookie;
67
+ short is_rfc3489_client = 0;
68
+
69
+ struct in_addr in_addr_ipv4;
70
+ struct in6_addr in_addr_ipv6;
71
+ uint16_t xor_port;
72
+ uint32_t xor_ipv4;
73
+ unsigned char xor_ipv6[16];
74
+
75
+ /* The size of our STUN Binding Response is the sum of:
76
+ * - STUN message header: 20 bytes.
77
+ * - One attribute (XOR-MAPPED-ADDRESS or MAPPED-ADDRESS).
78
+ * - Type + Length: 4 bytes.
79
+ * - XOR-MAPPED-ADDRESS or MAPPED-ADDRESS for IPv4: 4 + 4 = 8 bytes.
80
+ * - XOR-MAPPED-ADDRESS or MAPPED-ADDRESS for IPv6: 4 + 16 = 20 bytes.
81
+ * - Size for a response with IPv4: 20 + 4 + 8 = 32 bytes.
82
+ * - Size for a response with IPv6: 20 + 4 + 20 = 44 bytes.
83
+ */
84
+ char response[STUN_BINDING_SUCCESS_RESPONSE_IPV6_SIZE];
85
+
86
+ if (TYPE(rb_stun_request) != T_STRING)
87
+ rb_raise(rb_eTypeError, "First argument must be a String containing the STUN Binding Request");
88
+
89
+ request = RSTRING_PTR(rb_stun_request);
90
+
91
+ /* First octet of any STUN *request* must be 0. Return false otherwise. */
92
+ if (request[0]) {
93
+ LOG("first octet is not 0, so it's not a STUN request\n");
94
+ return Qnil;
95
+ }
96
+
97
+ /* Any STUN message must contain, at least, 20 bytes. Return false otherwise. */
98
+ if ((request_len = RSTRING_LEN(rb_stun_request)) < STUN_MESSAGE_MIN_SIZE) {
99
+ LOG("ERROR: request length less than 20 bytes, invalid STUN message\n");
100
+ return Qfalse;
101
+ }
102
+
103
+ if (TYPE(rb_source_ip) != T_STRING)
104
+ rb_raise(rb_eTypeError, "Third argument must be a String containing the source IP");
105
+
106
+ if (TYPE(rb_source_port) != T_FIXNUM)
107
+ rb_raise(rb_eTypeError, "Fourth argument must be a Fixnum containing the source port");
108
+
109
+ /*
110
+ * RFC 5389 section 6.
111
+ *
112
+ * a Binding request has class=0b00 (request) and method=0b000000000001 (Binding)
113
+ * and is encoded into the first 16 bits as 0x0001.
114
+ *
115
+ * So let's check the second byte which must be 0x1.
116
+ */
117
+ if ( request[1] != 0x1 ) {
118
+ LOG("ERROR: not a valid STUN Binding Request, maybe an STUN Indication (so ignore it)\n");
119
+ return Qfalse;
120
+ }
121
+
122
+ /*
123
+ * RFC 5389 section 6.
124
+ *
125
+ * The magic cookie field MUST contain the fixed value 0x2112A442 in network byte order.
126
+ *
127
+ * 0x21 = 33, 0x12 = 18, 0xA4 = -92, 0x42=66.
128
+ */
129
+ if (! (request[4] == 33 && request[5] == 18 && request[6] == -92 && request[7] == 66) ) {
130
+ LOG("WARN: STUN magic cookie does not match, using backward compatibility with RFC 3489\n");
131
+
132
+ /*
133
+ * RFC 5389 section 12.2.
134
+ *
135
+ * A STUN server can detect when a given Binding request message was
136
+ * sent from an RFC 3489 [RFC3489] client by the absence of the correct
137
+ * value in the magic cookie field. When the server detects an RFC 3489
138
+ * client, it SHOULD copy the value seen in the magic cookie field in
139
+ * the Binding request to the magic cookie field in the Binding response
140
+ * message, and insert a MAPPED-ADDRESS attribute instead of an
141
+ * XOR-MAPPED-ADDRESS attribute.
142
+ *
143
+ */
144
+ is_rfc3489_client = 1;
145
+ }
146
+
147
+ /* Get the Magic Cookie. */
148
+ magic_cookie = ((char *)request)+4;
149
+
150
+ /* Get the Transaction ID. */
151
+ transaction_id = ((char *)request)+8;
152
+
153
+ /*
154
+ * RFC 5389 section 6.
155
+ * "The message length MUST contain the size, in bytes, of the message
156
+ * not including the 20-byte STUN header. Since all STUN attributes are
157
+ * padded to a multiple of 4 bytes, the last 2 bits of this field are
158
+ * always zero. This provides another way to distinguish STUN packets
159
+ * from packets of other protocols."
160
+ *
161
+ */
162
+ message_length = ntohs(*(uint16_t *)(request+2));
163
+
164
+
165
+
166
+ /*
167
+ * Create the STUN Binding Response.
168
+ */
169
+
170
+ /* A Binding response has class=0b10 (success response) and method=*0b000000000001,
171
+ * and is encoded into the first 16 bits as 0x0101. */
172
+ response[0] = 1;
173
+ response[1] = 1;
174
+
175
+ /* Add the received Magic Cookie (for RFC 3489 backward compatibility). */
176
+ memcpy(response+4, magic_cookie, STUN_MAGIC_COOKIE_LEN);
177
+
178
+ /* Add the received Transaction Id. */
179
+ memcpy(response+8, transaction_id, STUN_TRANSACTION_ID_LEN);
180
+
181
+ /*
182
+ * Add an attribute XOR-MAPPED-ADDRESS (or MAPPED-ADDRESS if it's a RFC 3489 client).
183
+ */
184
+
185
+ /*
186
+ * STUN Attribute.
187
+ *
188
+ * 0 1 2 3
189
+ * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
190
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
191
+ * | Type | Length |
192
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
193
+ * | Value (variable) ....
194
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
195
+ *
196
+ *
197
+ * XOR-MAPPED-ADDRESS.
198
+ *
199
+ * 0 1 2 3
200
+ * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
201
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
202
+ * |x x x x x x x x| Family | X-Port |
203
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
204
+ * | X-Address (Variable)
205
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
206
+ *
207
+ *
208
+ * MAPPED-ADDRESS.
209
+ *
210
+ * 0 1 2 3
211
+ * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
212
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
213
+ * |0 0 0 0 0 0 0 0| Family | Port |
214
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
215
+ * | |
216
+ * | Address (32 bits or 128 bits) |
217
+ * | |
218
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
219
+ *
220
+ */
221
+
222
+ source_ip = StringValueCStr(rb_source_ip);
223
+
224
+ /* Check the IP and its type (IPv4 or IPv6). */
225
+ switch(inet_pton(AF_INET, source_ip, &in_addr_ipv4)) {
226
+ /* It's valid IPv4. */
227
+ case 1:
228
+ break;
229
+ /* Not valid INET family, hummmm. */
230
+ case -1:
231
+ LOG("ERROR: Family AF_INET (IPv4) not supported\n");
232
+ return Qfalse;
233
+ break;
234
+ /* Let's check with IPv6. */
235
+ case 0:
236
+ switch(inet_pton(AF_INET6, source_ip, &in_addr_ipv6)) {
237
+ /* It's valid IPv6. */
238
+ case 1:
239
+ source_ip_is_ipv6 = 1;
240
+ break;
241
+ /* Not valid INET family, hummmm. */
242
+ case -1:
243
+ LOG("ERROR: Family AF_INET6 (IPv6) not supported\n");
244
+ return Qfalse;
245
+ break;
246
+ /* The string is neither an IPv4 or IPv6. */
247
+ case 0:
248
+ LOG("ERROR: Unknown Address Family\n");
249
+ return Qfalse;
250
+ break;
251
+ }
252
+ }
253
+
254
+ /* Get the port in an integer (two bytes) */
255
+ source_port = (uint16_t)(FIX2INT(rb_source_port));
256
+
257
+ /* It's a RFC 5389 compliant client, so add XOR-MAPPED-ADDRESS. */
258
+ if (! is_rfc3489_client) {
259
+ /* STUN attribute type: 0x0020: XOR-MAPPED-ADDRESS */
260
+ response[20] = 0x00;
261
+ response[21] = 0x20;
262
+
263
+ /*
264
+ * XOR-MAPPED-ADDRESS fields.
265
+ */
266
+
267
+ /* First byte must be 0x00. */
268
+ response[24] = 0x00;
269
+
270
+ /* Second byte is the IP Family (0x01:IPv4, 0x02:IPv6). */
271
+ if (source_ip_is_ipv6)
272
+ response[25] = 0x02;
273
+ else
274
+ response[25] = 0x01;
275
+
276
+ /* Bytes 3 and 4 are the X-Port. X-Port is computed by taking the mapped port in
277
+ * host byte order, XOR'ing it with the most significant 16 bits of the magic cookie,
278
+ * and then the converting the result to network byte order. */
279
+ xor_port = htons(source_port ^ *(uint16_t *)(magic_cookie));
280
+
281
+ memcpy(response+26, &xor_port, 2);
282
+
283
+ /* Next bytes are the IP in network byte order with XOR stuff. */
284
+
285
+ /* IPv4. */
286
+ if (! source_ip_is_ipv6) {
287
+ /* If the IP address family is IPv4, X-Address is computed by taking the mapped IP
288
+ * address in host byte order, XOR'ing it with the magic cookie, and converting the
289
+ * result to network byte order. */
290
+ xor_ipv4 = htons((uint32_t)(in_addr_ipv4.s_addr) ^ *(uint32_t *)(magic_cookie));
291
+
292
+ memcpy(response+28, &xor_ipv4, 4);
293
+ /* So set the attribute Length to 8. */
294
+ response[22] = 0;
295
+ response[23] = 8;
296
+ /* So set the STUN Response Message Length to 12 bytes. */
297
+ response[2] = 0;
298
+ response[3] = 12;
299
+
300
+ /* Return the Ruby string containing the response. */
301
+ return rb_str_new(response, STUN_BINDING_SUCCESS_RESPONSE_IPV4_SIZE);
302
+ }
303
+ /* IPv6. */
304
+ else {
305
+ /* If the IP address family is IPv6, X-Address is computed by taking the
306
+ * mapped IP address in host byte order, XOR'ing it with the concatenation
307
+ * of the magic cookie and the 96-bit transaction ID, and converting the result
308
+ * to network byte order. */
309
+ /* NOTE: struct in_addr.s6_addr is an array of 16 char in network byte order (big-endian). */
310
+ /* TODO: So do I need to convert in_addr_ipv6.s6_addr to host byte order and later the
311
+ * whole result to network byte order? */
312
+ int i;
313
+ for(i=0; i<16; i++)
314
+ xor_ipv6[i] = in_addr_ipv6.s6_addr[i] ^ magic_cookie[i];
315
+
316
+ memcpy(response+28, xor_ipv6, 16);
317
+
318
+ /* So set the attribute Length to 20. */
319
+ response[22] = 0;
320
+ response[23] = 20;
321
+ /* So set the STUN Response Message Length to 24 bytes. */
322
+ response[2] = 0;
323
+ response[3] = 24;
324
+
325
+ /* Return the Ruby string containing the response. */
326
+ return rb_str_new(response, STUN_BINDING_SUCCESS_RESPONSE_IPV6_SIZE);
327
+ }
328
+ }
329
+
330
+ /* It's a RFC 3489 compliant client, so add MAPPED-ADDRESS. */
331
+ else {
332
+ /* STUN attribute type: 0x0001: MAPPED-ADDRESS */
333
+ response[20] = 0x00;
334
+ response[21] = 0x01;
335
+
336
+ /*
337
+ * MAPPED-ADDRESS fields.
338
+ */
339
+
340
+ /* First byte must be 0x00. */
341
+ response[24] = 0x00;
342
+
343
+ /* Second byte is the IP Family (0x01:IPv4, 0x02:IPv6). */
344
+ if (source_ip_is_ipv6)
345
+ response[25] = 0x02;
346
+ else
347
+ response[25] = 0x01;
348
+
349
+ /* Bytes 3 and 4 are the Port in network byte order. */
350
+ source_port = htons(source_port);
351
+ memcpy(response+26, &source_port, 2);
352
+
353
+ /* Next bytes are the IP in network byte order. */
354
+
355
+ /* IPv4. */
356
+ if (! source_ip_is_ipv6) {
357
+ memcpy(response+28, &in_addr_ipv4.s_addr, 4);
358
+ /* So set the attribute Length to 8. */
359
+ response[22] = 0;
360
+ response[23] = 8;
361
+ /* So set the STUN Response Message Length to 12 bytes. */
362
+ response[2] = 0;
363
+ response[3] = 12;
364
+
365
+ /* Return the Ruby string containing the response. */
366
+ return rb_str_new(response, STUN_BINDING_SUCCESS_RESPONSE_IPV4_SIZE);
367
+ }
368
+ /* IPv6. */
369
+ else {
370
+ memcpy(response+28, &in_addr_ipv6.s6_addr, 16);
371
+ /* So set the attribute Length to 20. */
372
+ response[22] = 0;
373
+ response[23] = 20;
374
+ /* So set the STUN Response Message Length to 24 bytes. */
375
+ response[2] = 0;
376
+ response[3] = 24;
377
+
378
+ /* Return the Ruby string containing the response. */
379
+ return rb_str_new(response, STUN_BINDING_SUCCESS_RESPONSE_IPV6_SIZE);
380
+ }
381
+ }
382
+
383
+ }
384
+
385
+
386
+ void Init_stun()
387
+ {
388
+ TRACE();
389
+
390
+ mOverSIP = rb_define_module("OverSIP");
391
+ mStun = rb_define_module_under(mOverSIP, "Stun");
392
+
393
+ rb_define_module_function(mStun, "parse_request", Stun_parse_request, 3);
394
+ }
@@ -0,0 +1,14 @@
1
+ #ifndef ext_help_h
2
+ #define ext_help_h
3
+
4
+ /* Uncomment for enabling TRACE() function. */
5
+ /*#define DEBUG*/
6
+
7
+ #ifdef DEBUG
8
+ #define TRACE() fprintf(stderr, "TRACE: %s:%d:%s\n", __FILE__, __LINE__, __FUNCTION__)
9
+ #else
10
+ #define TRACE()
11
+ #endif
12
+
13
+ #endif
14
+
@@ -0,0 +1,3 @@
1
+ require "mkmf"
2
+
3
+ create_makefile("oversip/utils")