2009-12-01 9 views
7

Je l'ai utilisé la pierre précieuse adresse IP et il ne semble pas avoir la capacité de convertir un masque de réseau de la formeNetmask à CIDR en rubis

255.255.255.0 

sous la forme CIDR

/24 

Est-ce que quelqu'un a des idées sur la façon de convertir rapidement le premier en le dernier?

+0

Une solution est probablement d'utiliser la gemme ipadmin au lieu qui ressemble beaucoup plus complet. Je suis toujours intéressé de voir quelle est la solution du point de vue du code. –

Répondre

11

Voici la façon rapide et sale

require 'ipaddr' 
puts IPAddr.new("255.255.255.0").to_i.to_s(2).count("1") 

Il devrait y avoir le bon fonctionnement pour cela, je ne pouvais pas trouver, donc je compte juste « 1 »

Si vous allez être en utilisant la fonction dans un certain nombre d'endroits et cela pourrait aider à ne pas l'esprit monkeypatching,:

IPAddr.class_eval 
    def to_cidr 
    "/" + self.to_i.to_s(2).count("1") 
    end 
end 

Ensuite, vous obtenez

IPAddr.new('255.255.255.0').to_cidr 
# => "/24" 
+0

Je ne suis pas sûr qu'il y ait quelque chose de plus approprié que d'utiliser count ("1"). Peut-être quelque chose comme ça? 32 - (2 ** 32 - 1 - IPAddr.new ("255.255.255.0"). To_i) .to_s (2).length' –

+0

En C, je vais probablement faire passer à droite, et tester avec & 1 jusqu'à sa portée 1, par exemple, 'bits = 32; unsigned int ipaddr = 0xFFFFFF00; while (ipaddr & 1 == 0) {ipaddr = ipaddr> > 1; bits -;} 'pour le cas ci-dessus, seulement besoin de passer à droite 8 fois je pense. – YOU

9

Tout comme un FYI, et de garder l'information facilement accessible pour ceux qui sont à la recherche ...

est ici un moyen simple de convertir au format CIDR netmask:

def cidr_to_netmask(cidr) 
    IPAddr.new('255.255.255.255').mask(cidr).to_s 
end 

Par exemple :

cidr_to_netmask(24) #=> "255.255.255.0" 
cidr_to_netmask(32) #=> "255.255.255.255" 
cidr_to_netmask(16) #=> "255.255.0.0" 
cidr_to_netmask(22) #=> "255.255.252.0" 
2

Si vous n'avez pas besoin d'utiliser gem-adresse IP, vous pouvez le faire avec le netaddr joyau

require 'netaddr' 

def to_cidr_mask(dotted_mask) 
    NetAddr::CIDR.create('0.0.0.0/'+dotted_mask).netmask 
end 

to_cidr_mask("255.224.0.0") # => "/11" 
4

est ici une approche plus mathématique, ce qui évite les chaînes à tout prix:

def cidr_mask 
    Integer(32-Math.log2((IPAddr.new(mask,Socket::AF_INET).to_i^0xffffffff)+1)) 
end 

avec « masque » étant une chaîne comme 255.255.255.0. Vous pouvez le modifier et remplacer le premier argument par "mask" si "mask" est déjà une représentation entière d'une adresse IP.

Ainsi, par exemple, si le masque était "255.255.255.0", IPAddr.new (masque, Socket de AF_INET) .to_i deviendrait 0xffffff00, qui est ensuite XOR avec 0xffffffff, qui est égal à 255.

Nous ajoutons 1 à cela pour faire une gamme complète de 256 hôtes, puis trouvons la base de log 2 de 256, qui est égale à 8 (les bits utilisés pour l'adresse hôte), puis soustraire 8 de 32, ce qui équivaut à 24 bits utilisés pour l'adresse réseau).

Nous avons ensuite converti en entier parce que Math.log2 renvoie un flottant.

4

conversion rapide et sale:

"255.255.255.0".split(".").map { |e| e.to_i.to_s(2).rjust(8, "0") }.join.count("1").split(".")

=> Je divisé masque dans un tableau

.map { |e| e.to_i.to_s(2).rjust(8, "0") }

=> Pour chaque élément en Array:

.to_i

=> Convertir en entier

.to_s(2)

=> Convertir entier en binaire

.rjust(8, "0")

=> Ajouter padding

=> Carte retourner un tableau avec la même cardinalité

.join

=> Convertir tableau dans une chaîne complète

.count("1")

=> Count "1" caractères => Donner masque CIDR

def mask_2_ciddr mask 
     "/" + mask.split(".").map { |e| e.to_i.to_s(2).rjust(8, "0") }.join.count("1").to_s 
    end 

    mask_2_ciddr "255.255.255.0" 
    => "/24" 
    mask_2_ciddr "255.255.255.128" 
    => "/25" 
1
require 'ipaddr' 

def serialize_ipaddr(address) 
    mask = address.instance_variable_get(:@mask_addr).to_s(2).count('1') 
    "#{address}/#{mask}" 
end 

serialize_ipaddr(IPAddr.new('192.168.0.1/24')) # => "192.168.0.0/24" 

Le code réalise le masquage en accédant privé instance variable * @ mask_addr) de l'instance IPAddr (adresse, passée dans serialize_ipaddr). Ce n'est pas ainsi recommandé (comme les variables d'instance ne font pas partie des classes API public, mais ici, il vaut mieux que l'analyse de la chaîne de #inspect à mon avis

Ainsi, le processus est le suivant:.

  1. obtenir la variable d'instance @mask_addr qui représente le masque de réseau
  2. obtenir sa représentation binaire, par exemple 255.255.255.0 -> 4294967040 -> 11111111111111111111111100000000
  3. Compte de la 1-s du nombre en base 2 pour obtenir le masque CIDR (24)
  4. Faire une chaîne constituée l'adresse & masque

EDIT: Ajout d'une explication à la mise en œuvre tel que demandé par NathanOliver

+0

Bien que cet extrait de code puisse résoudre la question, [y compris une explication] (http://meta.stackexchange.com/questions/114762/explaining-entirely- code-based-answers) aide vraiment à améliorer la qualité de votre poster. Rappelez-vous que vous répondez à la question pour les lecteurs dans le futur, et que ces personnes pourraient ne pas connaître les raisons de votre suggestion de code. – NathanOliver