diff --git a/ruby/trema/ipv4address.rb b/ruby/trema/ipv4address.rb new file mode 100644 index 00000000..4049c573 --- /dev/null +++ b/ruby/trema/ipv4address.rb @@ -0,0 +1,164 @@ +# +# Copyright (C) 2008-2013 NEC Corporation +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License, version 2, as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +# + + +module Trema + # + # IPv4 Address + # + class IPv4Address + require "ipaddr" + require "forwardable" + extend Forwardable + + + # + # @return [IPAddr] value object instance of proxied IPAddr. + # + attr_reader :value + + + # + # Creates a {IP} instance object as a proxy to IPAddr class. + # + # @overload initialize(ipv4address) + # + # @param [String] ipv4address + # an IPv4 address specified either as a String or Number. + # + # @raise [ArgumentError] invalid address if supplied argument is invalid + # IPv4 address. + # + # @return [IP] self + # a proxy to IPAddr. + # + def initialize ipv4address + if !ipv4address.kind_of? String + @value = IPAddr.new( ipv4address, Socket::AF_INET ) + else + @value = IPAddr.new( ipv4address ) + end + end + + + # + # @return [String] the IPv4 address in its text representation. + # + def_delegator :value, :to_s + + + # + # @return [Number] the IPv4 address in its numeric representation. + # + def_delegator :value, :to_i + + + # + # @return [Array] + # an array of decimal numbers converted from IPv4 address. + # + def to_a + to_s.split( "." ).collect do | each | + each.to_i + end + end + alias :to_array :to_a + + + # + # @return [IPv4Address] + # Returns the IPv4 address masked with masklen. + # + def mask! masklen + @value = @value.mask( masklen ) + return self + end + alias :prefix! :mask! + + + # + # @return [IPv4Address] + # Returns the IPv4 address masked with masklen. + # + def mask masklen + self.clone.mask!( masklen ) + end + alias :prefix :mask + + + # + # @return [bool] + # Returns true if the address belongs to class A. + # + def class_a? + mask( 1 ).to_s == "0.0.0.0" + end + + + # + # @return [bool] + # Returns true if the address belongs to class B. + # + def class_b? + mask( 2 ).to_s == "128.0.0.0" + end + + + # + # @return [bool] + # Returns true if the address belongs to class C. + # + def class_c? + mask( 3 ).to_s == "192.0.0.0" + end + + + # + # @return [bool] + # Returns true if the address belongs to class D. + # + def class_d? + mask( 4 ).to_s == "224.0.0.0" + end + alias :multicast? :class_d? + + + # + # @return [bool] + # Returns true if the address belongs to class E. + # + def class_e? + mask( 4 ).to_s == "240.0.0.0" + end + + + # + # @return [bool] + # Returns true if the address is unicast address. + # + def unicast? + class_a? or class_b? or class_c? + end + end +end + + +### Local variables: +### mode: Ruby +### coding: utf-8-unix +### indent-tabs-mode: nil +### End: diff --git a/ruby/trema/ipv6address.rb b/ruby/trema/ipv6address.rb new file mode 100644 index 00000000..f5f3fab8 --- /dev/null +++ b/ruby/trema/ipv6address.rb @@ -0,0 +1,161 @@ +# +# Copyright (C) 2008-2013 NEC Corporation +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License, version 2, as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +# + + +module Trema + # + # IPv6 Address + # + class IPv6Address + require "ipaddr" + require "forwardable" + extend Forwardable + + + # + # @return [IPAddr] value object instance of proxied IPAddr. + # + attr_reader :value + + + # + # Creates a {IPv6Address} instance object as a proxy to IPAddr class. + # + # @overload initialize(ipv6address) + # + # @param [String] ipv6address + # an IPv6 address specified either as a String or Number. + # + # @raise [ArgumentError] invalid address if supplied argument is invalid + # IPv6 address. + # + # @return [IP] self + # a proxy to IPAddr. + # + def initialize ipv6address + if !ipv6address.kind_of? String + @value = IPAddr.new( ipv6address, Socket::AF_INET6 ) + else + @value = IPAddr.new( ipv6address ) + end + end + + + # + # @return [String] the IPv6 address in its text representation. + # + def_delegator :value, :to_s + + + # + # @return [Number] the IPv6 address in its numeric representation. + # + def_delegator :value, :to_i + + + # + # @return [Array] + # an array of decimal numbers converted from IPv6 address. + # + def to_a + @value.hton.unpack( "C*" ) + end + alias :to_array :to_a + + + # + # @return [IPv6Address] + # Returns the IPv6 address masked with masklen. + # + def mask! masklen + @value = @value.mask( masklen ) + self + end + alias :prefix! :mask! + + + # + # @return [IPv6Address] + # Returns the IPv6 address masked with masklen. + # + def mask masklen + self.clone.mask!( masklen ) + end + alias :prefix :mask + + + # + # @return [bool] + # Returns true if the address is unspecified address (See rfc4291). + # + def unspecified? + to_s == "::" + end + + + # + # @return [bool] + # Returns true if the address is loopback address (See rfc 4291). + # + def loopback? + to_s == "::1" + end + + + # + # @return [bool] + # Returns true if the address is multicast address (See rfc4291). + # + def multicast? + mask( 8 ).to_s == "ff00::" + end + + + # + # @return [bool] + # Returns true if the address is link-local unicast address (See rfc4291). + # + def link_local_unicast? + mask( 10 ).to_s == "fe80::" + end + + + # + # @return [bool] + # Returns true if the address is global unicast address (See rfc4291). + # + def global_unicast? + not ( unspecified? or loopback? or multicast? or link_local_unicast? ) + end + + + # + # @return [bool] + # Returns true if the address is unicast address. + # + def unicast? + link_local_unicast? or global_unicast? + end + end +end + + +### Local variables: +### mode: Ruby +### coding: utf-8-unix +### indent-tabs-mode: nil +### End: diff --git a/spec/trema/ipv4address_spec.rb b/spec/trema/ipv4address_spec.rb new file mode 100644 index 00000000..b8bfc361 --- /dev/null +++ b/spec/trema/ipv4address_spec.rb @@ -0,0 +1,115 @@ +# +# Copyright (C) 2008-2013 NEC Corporation +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License, version 2, as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +# + + +require File.join( File.dirname( __FILE__ ), "..", "spec_helper" ) +require "trema/ipv4address" + + +describe IPv4Address, ".new( ip_address )" do + subject { IPv4Address.new( ip_address ) } + + + context "when 10.1.1.1" do + let( :ip_address ) { "10.1.1.1" } + + its( :to_s ) { should == "10.1.1.1" } + its( :to_i ) { should == ( ( 10 * 256 + 1 ) * 256 + 1 ) * 256 + 1 } + its( :to_array ) { should == [ 0x0a, 0x01, 0x01, 0x01 ] } + its( :class_a? ) { should == true } + its( :class_b? ) { should == false } + its( :class_c? ) { should == false } + its( :class_d? ) { should == false } + its( :class_e? ) { should == false } + its( :unicast? ) { should == true } + its( :multicast? ) { should == false } + end + + + context "when 172.20.1.1" do + let( :ip_address ) { "172.20.1.1" } + + its( :to_s ) { should == "172.20.1.1" } + its( :to_i ) { should == ( ( 172 * 256 + 20 ) * 256 + 1 ) * 256 + 1 } + its( :to_array ) { should == [ 0xac, 0x14, 0x01, 0x01 ] } + its( :class_a? ) { should == false } + its( :class_b? ) { should == true } + its( :class_c? ) { should == false } + its( :class_d? ) { should == false } + its( :class_e? ) { should == false } + its( :unicast? ) { should == true } + its( :multicast? ) { should == false } + end + + + context "when 192.168.1.1" do + let( :ip_address ) { "192.168.1.1" } + + its( :to_s ) { should == "192.168.1.1" } + its( :to_i ) { should == 3232235777 } + its( :to_array ) { should == [ 0xc0, 0xa8, 0x01, 0x01 ] } + its( :class_a? ) { should == false } + its( :class_b? ) { should == false } + its( :class_c? ) { should == true } + its( :class_d? ) { should == false } + its( :class_e? ) { should == false } + its( :unicast? ) { should == true } + its( :multicast? ) { should == false } + end + + + context "when 234.1.1.1" do + let( :ip_address ) { "234.1.1.1" } + + its( :to_s ) { should == "234.1.1.1" } + its( :to_i ) { should == ( ( 234 * 256 + 1 ) * 256 + 1 ) * 256 + 1 } + its( :to_array ) { should == [ 0xea, 0x01, 0x01, 0x01 ] } + its( :class_a? ) { should == false } + its( :class_b? ) { should == false } + its( :class_c? ) { should == false } + its( :class_d? ) { should == true } + its( :class_e? ) { should == false } + its( :unicast? ) { should == false } + its( :multicast? ) { should == true } + end +end + + +describe IPv4Address, ".mask!( mask )" do + subject { IPv4Address.new( ip_address ).mask!( mask ) } + + let( :ip_address ) { "10.1.1.1" } + let( :mask ) { 8 } + + its( :to_s ) { should == "10.0.0.0" } + its( :to_i ) { should == 10 * 256 * 256 * 256 } + its( :to_array ) { should == [ 0x0a, 0x00, 0x00, 0x00 ] } + its( :class_a? ) { should == true } + its( :class_b? ) { should == false } + its( :class_c? ) { should == false } + its( :class_d? ) { should == false } + its( :class_e? ) { should == false } + its( :unicast? ) { should == true } + its( :multicast? ) { should == false } +end + + +### Local variables: +### mode: Ruby +### coding: utf-8-unix +### indent-tabs-mode: nil +### End: diff --git a/spec/trema/ipv6address_spec.rb b/spec/trema/ipv6address_spec.rb new file mode 100644 index 00000000..770ff8a3 --- /dev/null +++ b/spec/trema/ipv6address_spec.rb @@ -0,0 +1,135 @@ +# +# Copyright (C) 2008-2013 NEC Corporation +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License, version 2, as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +# + + +require File.join( File.dirname( __FILE__ ), "..", "spec_helper" ) +require "trema/ipv6address" + + +describe IPv6Address, ".new( ipv6_address )" do + subject { IPv6Address.new( ipv6_address ) } + + + context "when unspecified" do + let( :ipv6_address ) { "::" } + + its( :to_s ) { should == "::" } + its( :to_i ) { should == 0 } + its( :to_array ) { should == [ 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00 ] } + its( :unspecified? ) { should == true } + its( :loopback? ) { should == false } + its( :multicast? ) { should == false } + its( :link_local_unicast? ) { should == false } + its( :global_unicast? ) { should == false } + its( :unicast? ) { should == false } + end + + + context "when loopback" do + let( :ipv6_address ) { "::1" } + + its( :to_s ) { should == "::1" } + its( :to_i ) { should == 1 } + its( :to_array ) { should == [ 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x01 ] } + its( :unspecified? ) { should == false } + its( :loopback? ) { should == true } + its( :multicast? ) { should == false } + its( :link_local_unicast? ) { should == false } + its( :global_unicast? ) { should == false } + its( :unicast? ) { should == false } + end + + + context "when multicast" do + let( :ipv6_address ) { "ff02::1" } + + its( :to_s ) { should == "ff02::1" } + its( :to_array ) { should == [ 0xff, 0x02, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x01 ] } + its( :unspecified? ) { should == false } + its( :loopback? ) { should == false } + its( :multicast? ) { should == true } + its( :link_local_unicast? ) { should == false } + its( :global_unicast? ) { should == false } + its( :unicast? ) { should == false } + end + + + context "when link-local" do + let( :ipv6_address ) { "fe80::1:1" } + + its( :to_s ) { should == "fe80::1:1" } + its( :to_array ) { should == [ 0xfe, 0x80, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x01, 0x00, 0x01 ] } + its( :unspecified? ) { should == false } + its( :loopback? ) { should == false } + its( :multicast? ) { should == false } + its( :link_local_unicast? ) { should == true } + its( :global_unicast? ) { should == false } + its( :unicast? ) { should == true } + end + + + context "when global unicast" do + let( :ipv6_address ) { "2001:db8::1" } + + its( :to_s ) { should == "2001:db8::1" } + its( :to_i ) { should == 42540766411282592856903984951653826561 } + its( :to_array ) { should == [ 0x20, 0x01, 0x0d, 0xb8, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x01 ] } + its( :unspecified? ) { should == false } + its( :loopback? ) { should == false } + its( :multicast? ) { should == false } + its( :link_local_unicast? ) { should == false } + its( :global_unicast? ) { should == true } + its( :unicast? ) { should == true } + end +end + + +describe IPv6Address, ".prefix( prefixlen )" do + subject { IPv6Address.new( ipv6_address ).prefix( prefixlen ) } + + let( :ipv6_address ) { "2001:db8:dead:beef::1" } + let( :prefixlen ) { 32 } + + its( :to_s ) { should == "2001:db8::" } + its( :to_i ) { should == 42540766411282592856903984951653826560 } + its( :to_array ) { should == [ 0x20, 0x01, 0x0d, 0xb8, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00 ] } +end + + +### Local variables: +### mode: Ruby +### coding: utf-8-unix +### indent-tabs-mode: nil +### End: