On Fri, Apr 25, 2003 at 03:43:11AM +0900, Hajimu UMEMOTO wrote:
> Hi,
> 
> Since I was not on the list, knu-san notified me of your mail.  So,
> I've just subscribed the list.

thank you.

> 
> >>>>> On Thu, 24 Apr 2003 19:34:14 +0200
> >>>>> "Stephane D'Alu" <Stephane.DAlu / nic.fr> said:
> 
> Stephane>  - having sub classes IPv4, IPv6 (and IPv6::Compatible) instead
> Stephane>    of one class doing it all (fall better in the object oriented design)
> 
> When I made ipaddr, I thought whether IPv4 and IPv6 should be
> implemented as separate class or not.  If IPv4 and IPv6 are separate
> classes, a user of the classes has to care which address family is
> using.  I prefer address family independent programing which means we
> don't care address family as possible.  So, I decide to implement it
> as one class.
> 

I totaly agree that the user in the general case shouldn't need to
choose between IPv4 or IPv6 (or even think about it), but I would
still like, as a programmer when doing "low network operations" be
able to know what kind of addresses are manipulated without asking
(ipv4? or ipv6? or ...)

I think we can manage to please both, the standard application programmer
and the picky network programmer, at the same time.

This would only require to have 
 - Address being a kind of abstract class, so that IPv4 or IPv6
   addresses have the same common behaviour inside an application
 - a class method in Address being able to return
   an object not of type Address but IPv4 or IPv6

I'm taking some part of my code as an illustration:

class Address
    class IPv4 < Address
       def create(..)
       end
    end

    class IPv6 < Address
       def create(..)
       end
    end

    OrderDefault        = [ Address::IPv4, Address::IPv6 ]

    def self.create(arg, order=OrderDefault)
        order.each { |klass|
            begin
                return klass::create(arg)
            rescue InvalidAddress
            end
        }
        raise InvalidAddress, "can't interpret #{arg.inspect} as address"
    end
end

With this approch we still give the possibility to the people who
want to use/implement IPv8, to do it easily ;->


So the network progammer who requires fine control can do:
  a = Address::IPv4::create("127.0.0.1")
  b = Address::IPv6::create("::1")
  case a
  when Address::IPv4
  when Address::IPv6
  end 

The application progammer who doesn't care do:
  a = Address::create("127.0.0.1")
  b = Address::create("::1")




> Stephane>  - when creating an address from a string, being able to select
> Stephane>    how the string should be interpreted (ipv4 or ipv4 mapped)
> Stephane>     (OrderStrict, OrderCompatibility, OrderIPv6Only, OrderIPv4Only)
> Stephane>    This will give finer control on the type of addresses that
> Stephane>    should be created (and could allow to easily swap to IPv6 only
> Stephane>    or remover IPv4 mapped addresses (there are already some talk about it))
> 
> It's a good idea.  Someone may want to traet an address strictly.

or in a year or two consider IPv6 as the default (ok, I'm optimistic ;)

> 
> Stephane>  - keeping some regular expression to test if a string match an ip address
> Stephane>     (IPv6StrictRegex, IPv6Regex, IPv6LooseRegex, ...)
> 
> How do you use these regular expressions?  I think it can be tested by
> whether a string can be converted to an address or not.

This would be use (as it was in resolv.rb) by doing:
case string_addr
when IPv6StrictRegex  # match IPv6 format only 
when IPv6LooseRegex   # match IPv6 and IPv4 (as it can be considerer as mapped)
end

So by saying that it can be tested by converting it, I assume that
some method using C code are called to do the job.

Now would it still be possible to create IPv6 addresses from string if
the system on which you are compiling ruby doesn't have support for
IPv6. I know this can seem a strange request, but you can want to
manipulate different addresss type even if they are not all supported
on your system (I'm in this case)


> 
> Stephane>  - having some commonly used constant defined (Loopback)
> 
> It's good idea having constant.  However, once we decide to have some
> constants, we need more constants than only Loopback.  This is why I
> didn't add constants, yet.

ok, so lets see, we can also add 'Wildcard'
 IPv4::Wildcard = '0.0.0.0'
 IPv6::Wildcard = '::'

this makes 2 ;)

and for more specific address type:
 IPv4 : broadcast = '255.255.255.255'
 IPv6 : link local all nodes   = 'FF02::1'
        link local all routers = 'FF02::2'

> 
> Stephane>  - the method name 'reverse' for ipaddr seems confusing when compared
> Stephane>    to class string or array
> 
> Yup, I think so.  Do you have any idea about the name?
> 

could be perhaps 'to_name' or 'to_dnsname' (or 'to_arpa' if we assume that
.ip6.int is deprecated as it should be, but I would prefer avoiding
this name)

> Stephane>  - scope_id or prefixlen are not directly part of an ip address
> Stephane>    and so should not be included in the class, if someone want/need
> Stephane>    them a new class should be created, this could be in the
> Stephane>    case of scope_id a class called SockAddr.
> 
> I implemented ipaddr as you say at the begining.  But, it was somewhat
> diffuse.  So, I merged these into one class.
> 
> Stephane>  - the | or & operator has some usefullness when dealing with netmask,
> Stephane>    but netmask and IPv4 classes (A, B, C, ..) have been depretiated in
> Stephane>    favor of prefixlen. now for the operators '<<' '>>' and '~', I should
> Stephane>    say that I have difficulties to find a real use for them.
> 
>
> It is useful when getting some part of the address or makeing IP
> address.  Especially, IPv6 address is structured.

this give the false feeling that the concept of netmask is still in use,
or that you can do bit operations over IP addresses
  c = a & b
will only give a usefull address c in a very precise condition
(and the shift operator seems even more hazardous)

Such low operations for IP address construction can already easily
be done in your code by: c = IPAddr::new(a.to_i & b.to_i)
As it can be done, I guess network programmers won't mind
this little extra step, and if they do it is easy in ruby to
add new methods to an already loaded class.

As a way of structuring IPv6, I would rather prefer a dedicated IPv6
class where the following methods are available:
 - eui64
 - prefix(len=64)
 - create_from_eui64
 - create_from_mac
 - in_net?(prefix, len=64)
 - link_local?
 - site_local?
 - anycast?
 - is_mapped?
 - is_compatible?
To implement all this method, I agree we will need the &, |, << ..,
but it will be possible to do it directly on @addr


It would also be nice, that we ensure that IP addresses are immutable
objects.

So in case you're wondering why I'm such annoying about IP addresses
(DNS will come later :), this is for this kind of application:
http://zonecheck.nic.fr/v2/

I would like to keep ruby libraries easy to use when in the general case,
but still powerful enough (or at least not removing the possibility to make it
powerful by overloading classes) when there is a need of a low level access.

Sincerly

-- 
Stephane D'Alu