# Programas
targets=ip
tests=test_send test_recv test_ipaddr test_ipin test_ipout test_devtcp \
- test_poll test_resolvprotos test_resolvprotoc
+ test_poll test_resolvprotos test_resolvprotoc test_nameserver_file
# Fuentes
fuentes ?= $(wildcard *.cpp) $(wildcard *.c)
test_resolvprotoc: test_resolvprotoc.o libtcp.o ipaddr.o resolvproto.o
+test_nameserver_file: test_nameserver_file.o ipaddr.o nameserver.o
+
ip: ip.o ipout.o ipin.o ipaddr.o ipheader.o devque.o devtcp.o routetable.o libtcp.o
depend:
ipout.o: /usr/include/sys/ipc.h /usr/include/bits/ipctypes.h
ipout.o: /usr/include/bits/ipc.h /usr/include/sys/msg.h
ipout.o: /usr/include/bits/msq.h
+nameserver.o: nameserver.h ipaddr.h /usr/include/stdint.h
+nameserver.o: /usr/include/features.h /usr/include/sys/cdefs.h
+nameserver.o: /usr/include/gnu/stubs.h /usr/include/bits/wchar.h
+nameserver.o: /usr/include/bits/wordsize.h
resolvproto.o: resolvproto.h ipaddr.h /usr/include/stdint.h
resolvproto.o: /usr/include/features.h /usr/include/sys/cdefs.h
resolvproto.o: /usr/include/gnu/stubs.h /usr/include/bits/wchar.h
test_ipout.o: /usr/include/sys/ipc.h /usr/include/bits/ipctypes.h
test_ipout.o: /usr/include/bits/ipc.h /usr/include/sys/msg.h
test_ipout.o: /usr/include/bits/msq.h
+test_nameserver_file.o: nameserver.h ipaddr.h /usr/include/stdint.h
+test_nameserver_file.o: /usr/include/features.h /usr/include/sys/cdefs.h
+test_nameserver_file.o: /usr/include/gnu/stubs.h /usr/include/bits/wchar.h
+test_nameserver_file.o: /usr/include/bits/wordsize.h
test_recv.o: devque.h dev.h /usr/include/unistd.h /usr/include/features.h
test_recv.o: /usr/include/sys/cdefs.h /usr/include/gnu/stubs.h
test_recv.o: /usr/include/bits/posix_opt.h /usr/include/bits/types.h
--- /dev/null
+#include "nameserver.h"
+#include <sstream>
+#include <algorithm>
+#include <iterator>
+#ifdef DEBUG2
+#include <iostream>
+#endif
+
+static void parsename(const std::string& s, NameServer::name_t& name)
+{
+ std::istringstream iss(s);
+ std::string tok;
+ while (std::getline(iss, tok, '.'))
+ {
+ name.push_back(tok);
+ }
+}
+
+static std::ostream& operator<< (std::ostream& os, const NameServer::name_t& name)
+{
+ if (name.empty())
+ return os;
+ std::copy(name.begin(), name.end() - 1,
+ std::ostream_iterator< std::string >(os, "."));
+ return os << name.back();
+}
+
+/// Parsea una zona
+static std::istream& parsezone(std::istream& is, NameServer::Zone& z)
+ throw (std::runtime_error)
+{
+ std::string line, sname, ip;
+ // [dominio] [ttl] [parent ip]
+ while (std::getline(is, line) && (line == "")); // Salteo líneas en blanco
+ if (!is)
+ return is;
+ std::istringstream iss(line);
+ if (!(iss >> sname >> z.ttl >> ip))
+ throw std::runtime_error("Error al parsear");
+ parsename(sname, z.name);
+#ifdef DEBUG2
+ std::cerr << "parsezone: IP = " << ip << "\n\n";
+#endif
+ z.parent = IPAddr(ip);
+ // un record por linea, sin líneas vacías
+ // [name] [type] [ip]
+ while (std::getline(is, line) && (line != ""))
+ {
+ iss.clear();
+ iss.str(line);
+ std::string key, type;
+ if (!(iss >> key >> type >> ip))
+ throw std::runtime_error("Error al parsear");
+ typedef NameServer::Record Rec;
+#ifdef DEBUG2
+ std::cerr << "parsezone: IP = " << ip << "\n\n";
+#endif
+ Rec r((type == "NS") ? Rec::NS : Rec::A, IPAddr(ip));
+ z.records.insert(NameServer::Zone::records_t::value_type(key, r));
+ }
+#ifdef DEBUG2
+ std::cerr << "parsezone: " << z << "\n\n";
+#endif
+ return is;
+}
+
+/// Constructor
+NameServer::Zone::Zone(std::string sname, size_t ttl, const IPAddr& parent):
+ ttl(ttl), parent(parent)
+{
+ parsename(sname, name);
+}
+
+/// Constructor
+NameServer::Zone::Zone(std::istream& is)
+ throw (std::runtime_error)
+{
+ // Parsea la zona
+ if (!parsezone(is, *this))
+ throw std::runtime_error("Error de parser, no hay zona");
+}
+
+/// Limpia una zona
+void NameServer::Zone::clear()
+{
+ name.clear();
+ records.clear();
+}
+
+/// Constructor
+NameServer::NameServer(std::istream& is)
+ throw (std::runtime_error)
+{
+ Zone z;
+ while (parsezone(is, z))
+ {
+ zones.push_back(z);
+ z.clear();
+#ifdef DEBUG2
+ std::cerr << "NameServer: " << z << "\n\n";
+#endif
+ }
+}
+
+std::ostream& operator<< (std::ostream& os, const NameServer::Record& r)
+{
+ if (r.type == NameServer::Record::NS)
+ os << "NS ";
+ else
+ os << "A ";
+ return os << r.ip;
+}
+
+std::ostream& operator<< (std::ostream& os,
+ const NameServer::Zone::records_t::value_type& p)
+{
+ return os << p.first << ": " << p.second;
+}
+
+std::ostream& operator<< (std::ostream& os, const NameServer::Zone& z)
+{
+ os << "Zone " << z.name << " " << z.ttl << " " << z.parent << "\n";
+ std::copy(z.records.begin(), z.records.end(), std::ostream_iterator<
+ NameServer::Zone::records_t::value_type >(os, "\n"));
+ return os;
+}
+
+std::ostream& operator<< (std::ostream& os, const NameServer& ns)
+{
+ os << "NameServer: zones[" << ns.zones.size() << "] (\n\n";
+ std::copy(ns.zones.begin(), ns.zones.end(),
+ std::ostream_iterator< NameServer::Zone >(os, "\n"));
+ return os << ")";
+}
+
+// vim: set et sw=4 sts=4 :
--- /dev/null
+#ifndef _NAMESERVER_H_
+#define _NAMESERVER_H_
+
+#include "ipaddr.h"
+//XXX#include "resolvproto.h"
+#include <string>
+#include <vector>
+#include <map>
+#include <istream>
+#include <ostream>
+#include <stdexcept>
+
+/// Petición del resolver a un nameserver
+struct NameServer
+{
+
+ /// Nombre de un dominio dividido en tokens
+ typedef std::vector< std::string > name_t;
+
+ /// Registro de una zona
+ struct Record
+ {
+ /// Tipo de registro
+ enum type_t { A, NS };
+ type_t type;
+ /// Dirección IP del registro
+ IPAddr ip;
+ /// Constructor
+ Record(type_t t, const IPAddr& i): type(t), ip(i) {}
+ };
+
+ /// Zona
+ struct Zone
+ {
+ /// Nombre
+ name_t name;
+ /// Time to live
+ size_t ttl;
+ /// Nodo padre
+ IPAddr parent;
+ /// Registros
+ typedef std::multimap< std::string, Record > records_t;
+ records_t records;
+ /// Constructores
+ Zone() {}
+ Zone(std::string sname, size_t ttl, const IPAddr& parent);
+ Zone(std::istream& is) throw (std::runtime_error);
+ /// Limpia una zona
+ void clear();
+ };
+
+ //TODO cache de _records_ (no zonas)
+
+ /// Zonas para las que este servidor de nombres es autoridad
+ typedef std::vector< Zone > zones_t;
+ zones_t zones;
+
+ /// Constructor
+ NameServer(std::istream& is) throw (std::runtime_error);
+
+};
+
+/// Impresión (para debug)
+std::ostream& operator<< (std::ostream& os, const NameServer& ns);
+std::ostream& operator<< (std::ostream& os, const NameServer::Record& r);
+std::ostream& operator<< (std::ostream& os, const NameServer::Zone& z);
+
+#endif // _NAMESERVER_H_
+
+// vim: set et sw=4 sts=4 :