Module: OverSIP::Utils

Defined in:
lib/oversip/utils.rb,
ext/utils/utils_ruby.c

Class Method Summary collapse

Class Method Details

.compare_ips(string1, string2) ⇒ Object

Returns true if both IP’s are equal (binary comparison). Returns false if both IP’s are not equal. Returns nil if at least one of the IP’s is not valid IPv4, IPv6 or IPv6 reference. This function also allows comparing an IPv6 with an IPv6 reference.



101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
# File 'ext/utils/utils_ruby.c', line 101

VALUE Utils_compare_ips(VALUE self, VALUE string1, VALUE string2)
{
  TRACE();
  char *str1, *str2;
  long len1, len2;
  enum enum_ip_type ip1_type, ip2_type;

  if (TYPE(string1) != T_STRING || TYPE(string2) != T_STRING)
    rb_raise(rb_eTypeError, "Arguments must be two String");

  str1 = RSTRING_PTR(string1);
  len1 = RSTRING_LEN(string1);
  str2 = RSTRING_PTR(string2);
  len2 = RSTRING_LEN(string2);

  switch(ip1_type = utils_ip_parser_execute(str1, len1)) {
    case(ip_type_error):
      return Qnil;
      break;
    case(ip_type_ipv6_reference):
      str1 += 1;
      len1 -= 2;
      ip1_type = ip_type_ipv6;
      break;
    default:
      break;
  }
  switch(ip2_type = utils_ip_parser_execute(str2, len2)) {
    case(ip_type_error):
      return Qnil;
      break;
    case(ip_type_ipv6_reference):
      str2 += 1;
      len2 -= 2;
      ip2_type = ip_type_ipv6;
      break;
    default:
      break;
  }

  if (utils_compare_pure_ips(str1, len1, ip1_type, str2, len2, ip2_type))
    return Qtrue;
  else
    return Qfalse;
}

.compare_pure_ips(string1, string2) ⇒ Object

Returns true if both IP’s are equal (binary comparison). Returns false if both IP’s are not equal. Returns nil if at least one of the IP’s is not valid IPv4 or IPv6. This function does not allow comparing an IPv6 with an IPv6 reference.



154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
# File 'ext/utils/utils_ruby.c', line 154

VALUE Utils_compare_pure_ips(VALUE self, VALUE string1, VALUE string2)
{
  TRACE();
  char *str1, *str2;
  long len1, len2;
  enum enum_ip_type ip1_type, ip2_type;

  if (TYPE(string1) != T_STRING || TYPE(string2) != T_STRING)
    rb_raise(rb_eTypeError, "Arguments must be two String");
  
  str1 = RSTRING_PTR(string1);
  len1 = RSTRING_LEN(string1);
  str2 = RSTRING_PTR(string2);
  len2 = RSTRING_LEN(string2);

  switch(ip1_type = utils_ip_parser_execute(str1, len1)) {
    case(ip_type_error):
      return Qnil;
      break;
    case(ip_type_ipv6_reference):
      return Qnil;
      break;
    default:
      break;
  }
  switch(ip2_type = utils_ip_parser_execute(str2, len2)) {
    case(ip_type_error):
      return Qnil;
      break;
    case(ip_type_ipv6_reference):
      return Qnil;
      break;
    default:
      break;
  }

  if (utils_compare_pure_ips(str1, len1, ip1_type, str2, len2, ip2_type))
    return Qtrue;
  else
    return Qfalse;
}

.ip?(string) ⇒ Boolean

Ruby functions.

Returns:

  • (Boolean)


21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
# File 'ext/utils/utils_ruby.c', line 21

VALUE Utils_is_ip(VALUE self, VALUE string)
{
  TRACE();
  char *str;
  long len;

  if (TYPE(string) != T_STRING)
    rb_raise(rb_eTypeError, "Argument must be a String");

  str = RSTRING_PTR(string);
  len = RSTRING_LEN(string);

  if (utils_ip_parser_execute(str, len) != ip_type_error)
    return Qtrue;
  else
    return Qfalse;
}

.ip_type(string) ⇒ Object



66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
# File 'ext/utils/utils_ruby.c', line 66

VALUE Utils_ip_type(VALUE self, VALUE string)
{
  TRACE();
  char *str;
  long len;
  
  if (TYPE(string) != T_STRING)
    rb_raise(rb_eTypeError, "Argument must be a String");

  str = RSTRING_PTR(string);
  len = RSTRING_LEN(string);

  switch(utils_ip_parser_execute(str, len)) {
    case(ip_type_ipv4):
      return symbol_ipv4;
      break;
    case(ip_type_ipv6):
      return symbol_ipv6;
      break;
    case(ip_type_ipv6_reference):
      return symbol_ipv6_reference;
      break;
    default:
      return Qfalse;
      break;
  }
}

.normalize_host(*args) ⇒ Object

Returns the normalized printable string of the given IPv4 or IPv6.

  • First argument is a string to normalize. It must be a valid IPv4, IPv6 or IPv6 reference. If not, the method returns the string itself.

  • Second argument is the type of host (:ipv4, :ipv6, :ipv6_reference or :domain).

  • Third argument is optional. If true, returned value is a pure IPv6 even if the first argument is a IPv6 reference.

TODO: Not in use and seems really ugly!



234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
# File 'ext/utils/utils_ruby.c', line 234

VALUE Utils_normalize_host(int argc, VALUE *argv, VALUE self)
{
  TRACE();
  VALUE host, ip_type;
  int force_pure_ipv6 = 0;

  if (argc == 0 || argc > 3)
    rb_raise(rb_eTypeError, "Wrong number of arguments (pass one, two or three)");

  host = argv[0];
  if (TYPE(host) != T_STRING)
    rb_raise(rb_eTypeError, "First argument must be a String");

  ip_type = argv[1];
  if (TYPE(ip_type) != T_SYMBOL)
    rb_raise(rb_eTypeError, "Second argument must be a Symbol (:ipv4, :ipv6 or :domain)");

  if (argc == 3 && TYPE(argv[2]) != T_NIL && TYPE(argv[2]) != T_FALSE)
    force_pure_ipv6 = 1;

  if (ip_type == symbol_ipv6 || ip_type == symbol_ipv6_reference)
    return utils_normalize_ipv6(host, force_pure_ipv6);
  else
    return host;
}

.normalize_ipv6(*args) ⇒ Object

Returns the normalized printable string of the given IPv6.

  • First argument is a string to normalize. It must be a valid IPv6 or IPv6 reference. If not, the method returns false.

  • Second argument is optional. If true, returned value is a pure IPv6 even if the first argument is a IPv6 reference.



204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
# File 'ext/utils/utils_ruby.c', line 204

VALUE Utils_normalize_ipv6(int argc, VALUE *argv, VALUE self)
{
  TRACE();
  VALUE string;
  int force_pure_ipv6 = 0;

  if (argc == 0 || argc > 2)
    rb_raise(rb_eTypeError, "Wrong number of arguments (pass one or two)");

  string = argv[0];
  if (TYPE(string) != T_STRING)
    rb_raise(rb_eTypeError, "First argument must be a String");

  if (argc == 2 && TYPE(argv[1]) != T_NIL && TYPE(argv[1]) != T_FALSE)
    force_pure_ipv6 = 1;

  return utils_normalize_ipv6(string, force_pure_ipv6);
}

.parse_haproxy_protocol(string) ⇒ Object

Expects a string like “PROXY TCP4 192.168.0.1 192.168.0.11 56324 443rn” and returns an Array as follows:

[ num_bytes, ip_type, ip, port ]

where:

- num_bytes is the length of the HAProxy Protocol line (to be removed), a Fixnum.
- ip_type is :ipv4 or :ipv6,
- ip is a String,
- port is a Fixnum

If the string is invalid it returns false.



338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
# File 'ext/utils/utils_ruby.c', line 338

VALUE Utils_parser_haproxy_protocol(VALUE self, VALUE string)
{
  TRACE();
  char *str = NULL;
  long len = 0;
  struct_haproxy_protocol haproxy_protocol;
  VALUE num_bytes, ip_type, ip, port;

  if (TYPE(string) != T_STRING)
    rb_raise(rb_eTypeError, "Argument must be a String");

  str = RSTRING_PTR(string);
  len = RSTRING_LEN(string);

  haproxy_protocol = struct_haproxy_protocol_parser_execute(str, len);

  if (haproxy_protocol.valid == 0)
    return Qfalse;
  else {
    if (haproxy_protocol.ip_type == haproxy_protocol_ip_type_ipv4)
      ip_type = symbol_ipv4;
    else
      ip_type = symbol_ipv6;

    ip = rb_str_new((char *)haproxy_protocol.ip_s, haproxy_protocol.ip_len);
    port = INT2FIX(str_to_int((char *)haproxy_protocol.port_s, haproxy_protocol.port_len));
    num_bytes = INT2FIX(haproxy_protocol.total_len);

    return rb_ary_new3(4, num_bytes, ip_type, ip, port);
  }
}

.parse_outbound_udp_flow_token(string) ⇒ Object

Expects a string like “1.2.3.4_5060” or “1af:43::ab_9090” and returns an Array as follows:

[ ip_type, ip, port ]

where:

- ip_type is :ipv4 or :ipv6,
- ip is a String,
- port is a Fixnum

If the string is invalid it returns false.



295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
# File 'ext/utils/utils_ruby.c', line 295

VALUE Utils_parser_outbound_udp_flow_token(VALUE self, VALUE string)
{
  TRACE();
  char *str = NULL;
  long len = 0;
  struct_outbound_udp_flow_token outbound_udp_flow_token;
  VALUE ip_type, ip, port;

  if (TYPE(string) != T_STRING)
    rb_raise(rb_eTypeError, "Argument must be a String");

  str = RSTRING_PTR(string);
  len = RSTRING_LEN(string);

  outbound_udp_flow_token = outbound_udp_flow_token_parser_execute(str, len);

  if (outbound_udp_flow_token.valid == 0)
    return Qfalse;
  else {
    if (outbound_udp_flow_token.ip_type == outbound_udp_flow_token_ip_type_ipv4)
      ip_type = symbol_ipv4;
    else
      ip_type = symbol_ipv6;

    ip = rb_str_new((char *)outbound_udp_flow_token.ip_s, outbound_udp_flow_token.ip_len);
    port = INT2FIX(str_to_int((char *)outbound_udp_flow_token.port_s, outbound_udp_flow_token.port_len));

    return rb_ary_new3(3, ip_type, ip, port);
  }
}

.pure_ip?(string) ⇒ Boolean

Returns:

  • (Boolean)


40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
# File 'ext/utils/utils_ruby.c', line 40

VALUE Utils_is_pure_ip(VALUE self, VALUE string)
{
  TRACE();
  char *str;
  long len;

  if (TYPE(string) != T_STRING)
    rb_raise(rb_eTypeError, "Argument must be a String");

  str = RSTRING_PTR(string);
  len = RSTRING_LEN(string);

  switch(utils_ip_parser_execute(str, len)) {
    case(ip_type_ipv4):
      return Qtrue;
      break;
    case(ip_type_ipv6):
      return Qtrue;
      break;
    default:
      return Qfalse;
      break;
  }
}

.regexp_compare(string, expression) ⇒ Object

This avoid “invalid byte sequence in UTF-8” when the directly doing:

string =~ /EXPRESSION/

and string has invalid UTF-8 bytes secuence. Also avoids “incompatible encoding regexp match (UTF-8 regexp with ASCII-8BIT string)” NOTE: expression argument must be a String or a Regexp.



18
19
20
21
22
23
24
25
26
# File 'lib/oversip/utils.rb', line 18

def self.regexp_compare string, expression
  string = string.to_s.force_encoding(::Encoding::BINARY)
  if expression.is_a? ::Regexp
    expression = /#{expression.source.force_encoding(::Encoding::BINARY)}/
  else
    expression = /#{expression.to_s.force_encoding(::Encoding::BINARY)}/
  end
  string =~ expression
end

.string_compare(string1, string2) ⇒ Object

It ensures that two identical byte secuences are matched regardless they have different encoding. For example in Ruby the following returns false:

"iñaki".force_encoding(::Encoding::BINARY) == "iñaki"


9
10
11
# File 'lib/oversip/utils.rb', line 9

def self.string_compare string1, string2
  string1.to_s.force_encoding(::Encoding::BINARY) == string2.to_s.force_encoding(::Encoding::BINARY)
end

.to_pure_ip(string) ⇒ Object

If the given argument is a IPV6 reference it returns a new string with the pure IPv6. In any other case, return the given argument.

TODO: Not documented in the API (seems ugly).



267
268
269
270
271
272
273
274
275
276
277
# File 'ext/utils/utils_ruby.c', line 267

VALUE Utils_to_pure_ip(VALUE self, VALUE string)
{
  TRACE();
  char *str;

  str = StringValueCStr(string);
  if (str[0] == '[')
    return rb_str_new(RSTRING_PTR(string)+1, RSTRING_LEN(string)-2);
  else
    return string;
}