162 lines
5.5 KiB
Python
162 lines
5.5 KiB
Python
# -*- coding: utf-8 -*-
|
||
#
|
||
# RIDTOOLS.PY -- Gestion de la conversion rid <-> IP
|
||
#
|
||
# Copyright (C) 2010 Olivier Iffrig
|
||
# (c) 2010 Nicolas Dandrimont
|
||
# Authors: Olivier Iffrig <iffrig@crans.org>
|
||
# Nicolas Dandrimont <olasd@crans.org>
|
||
# Adapté par Pierre-Elliott Bécue pour cause de changement de schéma.
|
||
#
|
||
# This program is free software: you can redistribute it and/or modify
|
||
# it under the terms of the GNU General Public License as published by
|
||
# the Free Software Foundation, either version 3 of the License, or
|
||
# (at your option) any later version.
|
||
#
|
||
# 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, see <http://www.gnu.org/licenses/>.
|
||
|
||
import netaddr
|
||
import itertools
|
||
import config
|
||
|
||
class Rid(object):
|
||
"""
|
||
Permet de décortiquer un rid et d'obtenir les IP correspondantes
|
||
|
||
Variables d'instance :
|
||
- rid : le rid
|
||
- type : type de rid (cf. config.rid et [1])
|
||
- reste : le "reste" du rid (permettant de calculer l'IP par exemple)
|
||
- ipv4_dispo : une IPv4 existe pour ce rid
|
||
- priv : cette machine ne doit pas être accessible de l'extérieur
|
||
|
||
[1] http://wiki.crans.org/CransTechnique/PlanAdressage#Machines
|
||
"""
|
||
|
||
def __init__(self, rid=None, ipv4=None):
|
||
self.rid = None
|
||
self.reste = False
|
||
self.type = None
|
||
self.ipv4_dispo = False
|
||
self.priv = False
|
||
|
||
if rid is not None:
|
||
self.__parse(rid)
|
||
elif ipv4 is not None:
|
||
self.__from_ipv4(ipv4)
|
||
else:
|
||
raise ValueError("Un des champs rid et ipv4 doit être défini")
|
||
|
||
def __parse(self, rid):
|
||
"""Peuple les champs de l'instance par rapport au rid"""
|
||
self.rid = rid
|
||
|
||
self.type = find_rid_plage(int(rid))
|
||
if self.type == 'Inconnu':
|
||
raise ValueError("rid inconnu : %d" % rid)
|
||
|
||
self.ipv4_dispo = (rid & (1 << 15)) == 0 and self.type != 'special' or self.rid in config.rid_machines_speciales
|
||
|
||
self.priv = (rid & (1 << 14)) != 0
|
||
|
||
if self.type == 'personnel-ens':
|
||
self.reste = rid & 0xff
|
||
else:
|
||
self.reste = rid & 0x7ff
|
||
|
||
def __from_ipv4(self, ip):
|
||
"""Peuple les champs à partir de l'ipv4 donnée"""
|
||
if not isinstance(ip, netaddr.IPAddress):
|
||
ip = netaddr.IPAddress(ip)
|
||
try:
|
||
ip.ipv4()
|
||
except netaddr.AddrConversionError:
|
||
raise ValueError("Ceci n'est pas une IPv4... %s" % ip)
|
||
|
||
self.ipv4_dispo = True
|
||
self.priv = ip.is_private()
|
||
|
||
for tp in config.NETs_primaires.keys():
|
||
for net in config.NETs_primaires[tp]:
|
||
if ip in netaddr.IPNetwork(net):
|
||
self.type = tp
|
||
break
|
||
if self.type:
|
||
break
|
||
else:
|
||
for rid, ip_speciale in config.rid_machines_speciales.items():
|
||
if ip == netaddr.IPAddress(ip_speciale):
|
||
self.rid = rid
|
||
self.type = "special"
|
||
break
|
||
else:
|
||
raise ValueError("%s dans aucun des réseaux gérés par le Cr@ns..." % ip)
|
||
|
||
ranges = itertools.chain(*[xrange(a, b+1) for (a,b) in config.rid[self.type]])
|
||
if not self.rid:
|
||
self.rid = config.rid[self.type][0][0] + ip.value - netaddr.IPNetwork(config.NETs[self.type][0]).value
|
||
|
||
if self.rid not in ranges:
|
||
raise ValueError("%s trop hors des plages prévues pour le réseau '%s'" % (ip, self.type))
|
||
|
||
if self.type == 'personnel-ens':
|
||
self.reste = self.rid & 0xff
|
||
else:
|
||
self.reste = self.rid & 0x7ff
|
||
return self.rid
|
||
|
||
def ipv4(self):
|
||
"""
|
||
Génère l'IPv4 associée à la machine
|
||
"""
|
||
if not self.ipv4_dispo:
|
||
raise ValueError("Pas d'adresse IPv4 disponible pour la machine %r" % self)
|
||
|
||
if not hasattr(self, '__ipv4'):
|
||
if self.type != "special":
|
||
net = netaddr.IPNetwork(config.NETs[self.type][0])
|
||
self.__ipv4 = netaddr.IPAddress(net.first + self.reste)
|
||
else:
|
||
self.__ipv4 = netaddr.IPAddress(config.rid_machines_speciales[self.rid])
|
||
|
||
return self.__ipv4
|
||
|
||
def ipv6_network(self):
|
||
"""
|
||
Génère le réseau /64 IPv6 associé à la machine
|
||
"""
|
||
if self.priv:
|
||
raise ValueError("Pas de prefix ipv6 disponible pour cette machine")
|
||
|
||
global_net = netaddr.IPNetwork(config.prefix["subnet"][0])
|
||
global_net.prefixlen = 64
|
||
return global_net.next(self.rid)
|
||
|
||
def __repr__(self):
|
||
if self.ipv4_dispo:
|
||
return "<Rid(rid=%s, ipv4='%s')>" % (self.rid, self.ipv4())
|
||
else:
|
||
return "<Rid(%s)>" % self.rid
|
||
|
||
def __int__(self):
|
||
return self.rid
|
||
|
||
def find_rid_plage(rid):
|
||
"""Trouve la plage du rid fourni"""
|
||
for (tp, plages) in config.rid_primaires.iteritems():
|
||
if isinstance(plages, list):
|
||
for begin, end in plages:
|
||
if begin <= rid <= end:
|
||
return tp, config.rid_primaires[tp][0]
|
||
else:
|
||
(begin, end) = plages
|
||
if begin <= rid <= end:
|
||
return tp, (begin, end)
|
||
else:
|
||
return "Inconnu", (0, 0)
|