--- /dev/null
+Esta es una estructura básica de lo que puede ser el daemon, con el mecanismo
+básico de despacho de comandos.
+
+Para correr el ejemplo:
+python pollserver.py
+
+luego desde otra consola escribir, podemos comunicarnos via netcat:
+nc localhost 9999
+
+y mandar comandos que comiencen con 'test':
+test alal dldl flkg
+
+En la ventana del server debería aparecer algo como:
+test: ('alal', 'dldl', 'flkg')
+
+Si no empieza con 'test' va a explotar el server porque todavía no tiene manejo
+de errores, pero es fácil ponerlo.
+
+Para hacer una prueba simple del dispatcher: python dispatcher.py
+
+http://www.cisco.com/en/US/products/sw/iosswrel/ps5187/prod_command_reference_list.html
\ No newline at end of file
--- /dev/null
+
+Configuracion de dhcp server:
+
+Variables globales:
+
+%(domain_name) = Nombre del dominio
+%(dns_1) = DNS primario
+%(dns_2) = DNS secundario
+%(net_address) = Direccion de la red que se va a servir por DHCP
+%(net_mask) = Mascara de la red
+%(net_start) = Direccion inicial del rango de direcciones dinamicas
+%(net_end) = Direccion final del rango de direcciones dinamicas
+%(net_gateway) = Puerta de enlace de la red
+
+
+Y esto es por host:
+
+%(host1_name) = Nombre del host
+%(host1_mac) = MAC Address del host (ej. 00:00:12:34:56:78)
+%(host1_ip) = Direccion IP del host
+
+----------------8<----------------------------------------------------
+
+ddns-update-style none;
+
+option domain-name %(domain_name);
+option domain-name-servers %(dns_1), %(dns_2);
+
+authoritative;
+
+log-facility local7;
+
+subnet %(net_address) netmask %(net_mask) {
+ range %(net_start) %(net_end);
+ option routers %(net_gateway);
+}
+
+host %(host1_name) {
+ fixed-address %(host1_ip);
+ hardware ethernet %(host1_mac);
+}
--- /dev/null
+Variables
+
+%(ns1) = Servidor de nombres de la zona (dominio)
+%(ns2) = Servidor de nombres de la zona (dominio)
+
+%(zone1) = Nombre de la zona (dominio)
+%(host_name1) = Nombre del host 1 (sin dominio)
+%(host_name2) = Nombre del host 2 (sin dominio)
+
+
+
+------------------8<---------------
+
+$TTL 1W
+@ IN SOA %(ns1).%(zone1). root.%(zone1). (
+ 2002081601 ; Serial
+ 28800 ; Refresh
+ 14400 ; Retry
+ 604800 ; Expire - 1 week
+ 86400 ) ; Minimum
+@ IN NS %(ns1)
+
+%(host_name1) IN A %(host_ip1)
+%(host_name2) IN A %(host_ip2)
+
--- /dev/null
+Servidor DNS
+
+
+Variables:
+
+
+%(isp_dns1) = Servidor primario del proveedor de internet
+%(isp_dns2) = Servidor secundario del proveedor de internet
+%(bind_addr1) = Direccion ip donde va a "escuchar" el servidor de dns
+%(bind_addr2) = Direccion ip donde va a "escuchar" el servidor de dns
+%(zone1) = "Zona" o dominio que va a manejar este DNS
+%(zone2) = "Zona" o dominio que va a manejar este DNS
+
+-----------8<-------------------------------------------------------------
+options {
+ directory "/var/bind";
+
+ forward first;
+ forwarders {
+ %(isp_dns1);
+ %(isp_dns2);
+ };
+
+ listen-on-v6 { none; };
+ listen-on {
+ %(bind_addr1);
+ %(bind_addr2);
+ };
+
+ pid-file "/var/run/named/named.pid";
+};
+
+zone "." IN {
+ type hint;
+ file "named.ca";
+};
+
+zone "localhost" IN {
+ type master;
+ file "pri/localhost.zone";
+ allow-update { none; };
+ notify no;
+};
+
+zone "127.in-addr.arpa" IN {
+ type master;
+ file "pri/127.zone";
+ allow-update { none; };
+ notify no;
+};
+
+zone "%(zone1)" IN {
+ type master;
+ file "pri/%(zone1).zone";
+ allow-update { none; };
+ notify no;
+};
+
+zone "%(zone1)" IN {
+ type master;
+ file "pri/%(zone1).zone.ptr";
+ allow-update { none; };
+ notify no;
+};
+
+zone "%(zone2)" IN {
+ type master;
+ file "pri/%(zone2).zone";
+ allow-update { none; };
+ notify no;
+};
+
+zone "%(zone2)" IN {
+ type master;
+ file "pri/%(zone2).zone.ptr";
+ allow-update { none; };
+ notify no;
+};
+
--- /dev/null
+ddns-update-style none;
+
+option domain-name baryon.com.ar;
+option domain-name-servers my_ns1, my_ns2;
+
+authoritative;
+
+log-facility local7;
+
+subnet 192.168.0.0 netmask 255.255.255.0 {
+ range 192.168.0.100 192.168.0.200;
+ option routers 192.168.0.1;
+}
+
+host my_name {
+ fixed-address 192.168.0.192;
+ hardware ethernet 00:12:ff:56;
+}
+
+host nico {
+ fixed-address 192.168.0.188;
+ hardware ethernet 00:00:00:00;
+}
--- /dev/null
+
+import pickle
+
+class ParamsError(Exception):
+ def __init__(self,reason):
+ self.reason = reason
+
+ def __str__(self):
+ return repr(reason)
+
+class dhcpd:
+ "class that handles dhcpd config"
+
+ def __init__(self):
+ self.host_list = dict()
+ self.glob = { 'domain_name' : 'my_domain_name',
+ 'dns_1' : 'my_ns1',
+ 'dns_2' : 'my_ns2',
+ 'net_address' : '192.168.0.0',
+ 'net_mask' : '255.255.255.0',
+ 'net_start' : '192.168.0.100',
+ 'net_end' : '192.168.0.200',
+ 'net_gateway' : '192.168.0.1'}
+
+
+ def to_file_format(self):
+ #bajo los parametros globales
+ glob_file = open('dhcpd_global.template','r')
+ glob_tmp = glob_file.read()
+ glob_file.close()
+ conf = glob_tmp % self.glob
+ #bajo los hosts
+ host_file = open('dhcpd_host.template','r')
+ host_tmp = host_file.read()
+ host_file.close()
+ for h , v in self.host_list.iteritems():
+ conf = conf + '\n' + (host_tmp % v)
+ return conf
+
+ def add_host(self, args):
+ #deberia indexar por hostname o por ip?
+ if len(args) == 3:
+ self.host_list[args[0]] = {"host_name": args[0], "host_ip": args[1], "host_mac": args[2]}
+ else:
+ raise ParamsError('Wrong number of parameters')
+
+ def mod_host(self, args):
+ #deberia indexar por hostname o por ip?
+ if len(args) == 3:
+ self.host_list[args[0]] = {"host_name": args[0], "host_ip": args[1], "host_mac": args[2]}
+ else:
+ raise ParamsError('Wrong number of parameters')
+
+ def remove_host(self, hostname):
+ if hostname in self.host_list:
+ del(self.host_list[hostname])
+ else:
+ raise ParamsError("No such host")
+
+ def set(self, pair):
+ if pair[0] in self.glob:
+ self.glob[pair[0]] = pair[1]
+ else:
+ raise ParamsError("Parameter " + pair[0] + " not found")
+
+ def start(self):
+ #esto seria para poner en una interfaz
+ #y seria el hook para arrancar el servicio
+ pass
+
+ def stop(self):
+ #esto seria para poner en una interfaz
+ #y seria el hook para arrancar el servicio
+ pass
+
+ def commit(self):
+ #esto seria para poner en una interfaz
+ #y seria que hace el pickle deberia llamarse
+ #al hacerse un commit
+ output = open('dhcpd_config.pkl', 'wb')
+ pickle.dump(config, output)
+ output.close()
+
+ def show_params(self):
+ string = ''
+ for k , v in self.glob.iteritems():
+ string = string + k + ' : ' + v + '\n'
+ return string
+
+ def show_hosts(self):
+ string = ''
+ for k , v in self.host_list.iteritems():
+ string = string + k + ' : ' + v["host_ip"] + ' : ' + v["host_mac"] + '\n'
+ return string
+
+
+if __name__ == '__main__':
+
+ config = dhcpd()
+
+ try :
+ arguments = ('my_name','192.168.0.102','00:12:ff:56')
+ config.add_host(arguments)
+
+ arguments = ('my_name','192.168.0.192','00:12:ff:56')
+ config.mod_host(arguments)
+
+ arguments = ('nico','192.168.0.188','00:00:00:00')
+ config.add_host(arguments)
+
+ config.set(('domain_name','baryon.com.ar'))
+ config.set(('sarasa','baryon.com.ar'))
+
+ except ParamsError, inst:
+ print inst.reason
+
+ config.commit()
+
+ conf_file = open('dhcpd.conf','w')
+ conf_file.write(config.to_file_format())
+ conf_file.close()
--- /dev/null
+(i__main__
+dhcpd
+p0
+(dp1
+S'glob'
+p2
+(dp3
+S'net_end'
+p4
+S'192.168.0.200'
+p5
+sS'net_mask'
+p6
+S'255.255.255.0'
+p7
+sS'domain_name'
+p8
+S'baryon.com.ar'
+p9
+sS'dns_1'
+p10
+S'my_ns1'
+p11
+sS'dns_2'
+p12
+S'my_ns2'
+p13
+sS'net_start'
+p14
+S'192.168.0.100'
+p15
+sS'net_gateway'
+p16
+S'192.168.0.1'
+p17
+sS'net_address'
+p18
+S'192.168.0.0'
+p19
+ssS'host_list'
+p20
+(dp21
+S'my_name'
+p22
+(dp23
+S'host_name'
+p24
+g22
+sS'host_mac'
+p25
+S'00:12:ff:56'
+p26
+sS'host_ip'
+p27
+S'192.168.0.192'
+p28
+ssS'nico'
+p29
+(dp30
+g24
+g29
+sg25
+S'00:00:00:00'
+p31
+sg27
+S'192.168.0.188'
+p32
+sssb.
\ No newline at end of file
--- /dev/null
+ddns-update-style none;
+
+option domain-name %(domain_name)s;
+option domain-name-servers %(dns_1)s, %(dns_2)s;
+
+authoritative;
+
+log-facility local7;
+
+subnet %(net_address)s netmask %(net_mask)s {
+ range %(net_start)s %(net_end)s;
+ option routers %(net_gateway)s;
+}
--- /dev/null
+host %(host_name)s {
+ fixed-address %(host_ip)s;
+ hardware ethernet %(host_mac)s;
+}
--- /dev/null
+# vim: set et sts=4 sw=4 encoding=utf-8 :
+
+class BadRouteError(Exception):
+
+ def __init__(self,cmd):
+ self.cmd = cmd
+
+ def __str__(self):
+ return repr(cmd)
+
+class CommandNotFoundError(Exception):
+
+ def __init__(self,cmd):
+ self.cmd = cmd
+
+ def __str__(self):
+ return repr(cmd)
+
+class Dispatcher:
+
+ def __init__(self, routes=dict()):
+ self.routes = routes
+
+ def dispatch(self, route):
+ route = route.split() # TODO considerar comillas
+ try:
+ handler = self.routes[route[0]]
+ route = route[1:]
+ while not callable(handler):
+ handler = getattr(handler, route[0])
+ route = route[1:]
+ handler(*route)
+
+ except KeyError:
+ raise CommandNotFoundError(route[0])
+ except AttributeError:
+ raise BadRouteError(route[0])
+ except IndexError:
+ pass
+
+
+def test_func(*args):
+ print 'func:', args
+
+
+class TestClassSubHandler:
+
+ def subcmd(self, *args):
+ print 'class.subclass.subcmd:', args
+
+
+class TestClass:
+
+ def cmd1(self, *args):
+ print 'class.cmd1:', args
+
+ def cmd2(self, *args):
+ print 'class.cmd2:', args
+
+ subclass = TestClassSubHandler()
+
+
+if __name__ == '__main__':
+
+ d = Dispatcher(dict(
+ func=test_func,
+ inst=TestClass(),
+ ))
+
+ d.dispatch('func arg1 arg2 arg3')
+ d.dispatch('inst cmd1 arg1 arg2 arg3 arg4')
+ d.dispatch('inst subclass subcmd arg1 arg2 arg3 arg4 arg5')
+
+# Ideas / TODO:
+#
+# * Soportar comillas para argumentos con espacios y otros caracteres, onda:
+# 'misc set motd "Hola!\nEste es el servidor de garombia"'
+#
+# * Soportar keyword arguments, onda que:
+# 'dns set pepe=10.10.10.1 juan=10.10.10.2'
+# se mapee a algo como: dns.set(pepe='10.10.10.1', juan='10.10.10.2')
+#
+# Estas cosas quedan sujetas a necesitada y a definición del protocolo.
+# Para mí lo ideal es que el protocolo de red sea igual que la consola del
+# usuario, porque después de todo no va a ser más que eso, mandar comanditos.
+#
+# Por otro lado, el cliente de consola, por que no es el cliente web pero
+# accedido via ssh usando un navegador de texto como w3m???
+
--- /dev/null
+# vim: set encoding=utf-8 et sw=4 sts=4 :
+
+import signal
+import select
+from sys import exit
+
+import dispatcher as dis
+import udp_server as us
+
+def quit(signum, frame):
+ print "Shuting down ..."
+ exit(0)
+
+signal.signal(signal.SIGINT, quit)
+signal.signal(signal.SIGTERM, quit)
+
+server = us.UDPServer(9999)
+
+poll = select.poll()
+poll.register(server.sock.fileno(), select.POLLIN | select.POLLPRI)
+
+d = dis.Dispatcher(dict(
+ func=dis.test_func,
+ inst=dis.TestClass()
+ ))
+
+def handle_recv(sock):
+ (msg, addr) = sock.recvfrom(65535)
+ try:
+ d.dispatch(msg)
+ except dis.BadRouteError, inst:
+ sock.sendto('Bad route from : ' + inst.cmd + '\n', addr)
+ except dis.CommandNotFoundError, inst:
+ sock.sendto('Command not found : ' + inst.cmd + '\n', addr)
+
+while True:
+ l = poll.poll()
+ handle_recv(server.sock)
+
--- /dev/null
+# vim: set encoding=utf-8 et sw=4 sts=4 :
+
+import socket as s
+
+class UDPServer:
+ "Udp server class"
+
+ def __init__(self, port):
+ self.sock = s.socket(s.AF_INET, s.SOCK_DGRAM)
+ self.sock.setsockopt(s.SOL_SOCKET, s.SO_REUSEADDR, 1)
+ self.sock.bind(('', port))
\ No newline at end of file