Browse Source

[trac878] simple DHCPv6 echo server implemented:
- Added Addr6 (IPv6 address wrapper)
- Added Pkt6 (generic IPv6 packet class)
- Added IfaceMgr (provides information about available interfaces,
opens sockets, sends and receives packets)
- Added Dhcpv6Srv - a dummy echo server for now

Tomek Mrugalski 14 years ago
parent
commit
d3ef968244

+ 4 - 5
src/bin/dhcp6/Makefile.am

@@ -19,7 +19,7 @@ pkglibexecdir = $(libexecdir)/@PACKAGE@
 CLEANFILES = *.gcno *.gcda spec_config.h
 
 man_MANS = b10-dhcp6.8
-EXTRA_DIST = $(man_MANS) dhcp6.spec
+EXTRA_DIST = $(man_MANS) dhcp6.spec interfaces.txt
 
 #if ENABLE_MAN
 #b10-dhcp6.8: b10-dhcp6.xml
@@ -31,8 +31,8 @@ spec_config.h: spec_config.h.pre
 
 BUILT_SOURCES = spec_config.h
 pkglibexec_PROGRAMS = b10-dhcp6
-b10_dhcp6_SOURCES = main.cc
-b10_dhcp6_SOURCES += dhcp6.h
+b10_dhcp6_SOURCES = main.cc addr6.cc iface_mgr.cc pkt6.cc dhcp6_srv.cc 
+b10_dhcp6_SOURCES += addr6.h iface_mgr.h pkt6.h dhcp6_srv.h dhcp6.h
 b10_dhcp6_LDADD =  $(top_builddir)/src/lib/datasrc/libdatasrc.la
 b10_dhcp6_LDADD += $(top_builddir)/src/lib/dns/libdns++.la
 b10_dhcp6_LDADD += $(top_builddir)/src/lib/config/libcfgclient.la
@@ -48,5 +48,4 @@ b10_dhcp6_LDADD += $(SQLITE_LIBS)
 # TODO: config.h.in is wrong because doesn't honor pkgdatadir
 # and can't use @datadir@ because doesn't expand default ${prefix}
 b10_dhcp6dir = $(pkgdatadir)
-b10_dhcp6_DATA = dhcp6.spec
-
+b10_dhcp6_DATA = dhcp6.spec interfaces.txt

+ 83 - 0
src/bin/dhcp6/addr6.cc

@@ -0,0 +1,83 @@
+// Copyright (C) 2011  Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#include <string.h>
+#include <arpa/inet.h>
+
+#include <ostream>
+
+#include "dhcp6/addr6.h"
+
+std::ostream & isc::operator << (std::ostream & out, const isc::Addr6& addr) {
+    out << addr.getPlain();
+    return out;
+}
+
+using namespace std;
+using namespace isc;
+
+Addr6::Addr6(const char *addr, bool plain /*=false*/) {
+    if (plain) {
+        inet_pton(AF_INET6, addr, addr_);
+    } else {
+        memcpy(addr_, addr, 16);
+    }
+}
+
+Addr6::Addr6() {
+    memset(addr_, 0, 16);
+}
+
+Addr6::Addr6(in6_addr* addr) {
+    memcpy(addr_, addr, 16);
+}
+
+Addr6::Addr6(sockaddr_in6* addr) {
+    memcpy(addr_, &addr->sin6_addr, 16);
+}
+
+bool Addr6::linkLocal() const {
+    if ( ( (unsigned char)addr_[0]==0xfe) &&
+         ( (unsigned char)addr_[1]==0x80) ) {
+        return true;
+    } else {
+        return false;
+    }
+}
+
+bool Addr6::multicast() const {
+    if ( (unsigned char)addr_[0]==0xff) {
+        return true;
+    } else {
+        return false;
+    }
+}
+
+std::string Addr6::getPlain() const {
+    char buf[MAX_ADDRESS_STRING_LEN];
+
+    inet_ntop(AF_INET6, addr_, buf, MAX_ADDRESS_STRING_LEN);
+    return string(buf);
+}
+
+
+bool Addr6::operator==(const Addr6& other) const {
+    if (!memcmp(addr_, other.addr_, 16)) {
+        return true;
+    } else {
+        return false;
+    }
+
+    // return !memcmp() would be shorter, but less readable
+}

+ 53 - 0
src/bin/dhcp6/addr6.h

@@ -0,0 +1,53 @@
+// Copyright (C) 2011  Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#ifndef ADDR6_H
+#define ADDR6_H
+
+#include <ostream>
+#include <string>
+#include <list>
+
+namespace isc {
+
+    static const int MAX_ADDRESS_STRING_LEN =
+        sizeof("ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255");
+
+    class Addr6 {
+    public:
+        Addr6(const char * addr, bool plain=false);
+        Addr6(struct in6_addr* addr);
+        Addr6(struct sockaddr_in6 * addr);
+        Addr6();
+        inline const char * get() const { return addr_; }
+        std::string getPlain() const;
+        char * get() { return addr_; }
+        bool operator==(const Addr6& other) const;
+
+        bool linkLocal() const;
+        bool multicast() const;
+
+        // no dtor necessary (no allocations done)
+    private:
+        char addr_[MAX_ADDRESS_STRING_LEN];
+    };
+
+    std::ostream & operator << (std::ostream & out, const Addr6& addr);
+
+    typedef std::list<Addr6> Addr6Lst;
+
+};
+
+
+#endif

+ 22 - 51
src/bin/dhcp6/dhcp6.h

@@ -1,29 +1,19 @@
-/* dhcp6.h
-
-   DHCPv6 Protocol structures... */
-
-/*
- * Copyright (c) 2006-2011 by Internet Systems Consortium, Inc. ("ISC")
- *
- * Permission to use, copy, modify, and distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
- * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- *
- *   Internet Systems Consortium, Inc.
- *   950 Charter Street
- *   Redwood City, CA 94063
- *   <info@isc.org>
- *   https://www.isc.org/
- */
-
+// Copyright (C) 2006-2011  Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#ifndef DHCP6_H
+#define DHCP6_H
 
 /* DHCPv6 Option codes: */
 
@@ -136,8 +126,11 @@ extern const int dhcpv6_type_name_max;
 /* 
  * DHCPv6 well-known multicast addressess, from section 5.1 of RFC 3315 
  */
-#define All_DHCP_Relay_Agents_and_Servers "FF02::1:2"
-#define All_DHCP_Servers "FF05::1:3"
+#define ALL_DHCP_RELAY_AGENTS_AND_SERVERS "FF02::1:2"
+#define ALL_DHCP_SERVERS "FF05::1:3"
+
+#define DHCP6_CLIENT_PORT 546
+#define DHCP6_SERVER_PORT 547
 
 /*
  * DHCPv6 Retransmission Constants (RFC3315 section 5.5, RFC 5007)
@@ -171,29 +164,6 @@ extern const int dhcpv6_type_name_max;
 #define LQ6_MAX_RT       10
 #define LQ6_MAX_RC        5
 
-/* 
- * Normal packet format, defined in section 6 of RFC 3315 
- */
-struct dhcpv6_packet {
-	unsigned char msg_type;
-	unsigned char transaction_id[3];
-	unsigned char options[FLEXIBLE_ARRAY_MEMBER];
-};
-
-/* Offset into DHCPV6 Reply packets where Options spaces commence. */
-#define REPLY_OPTIONS_INDEX 4
-
-/* 
- * Relay packet format, defined in section 7 of RFC 3315 
- */
-struct dhcpv6_relay_packet {
-	unsigned char msg_type;
-	unsigned char hop_count;
-	unsigned char link_address[16];
-	unsigned char peer_address[16];
-	unsigned char options[FLEXIBLE_ARRAY_MEMBER];
-};
-
 /* Leasequery query-types (RFC 5007) */
 
 #define LQ6QT_BY_ADDRESS	1
@@ -211,3 +181,4 @@ struct dhcpv6_relay_packet {
 #define IRT_DEFAULT	86400
 #define IRT_MINIMUM	600
 
+#endif

+ 46 - 0
src/bin/dhcp6/dhcp6_srv.cc

@@ -0,0 +1,46 @@
+// Copyright (C) 2011  Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#include "dhcp6/addr6.h"
+#include "dhcp6/pkt6.h"
+#include "dhcp6/iface_mgr.h"
+#include "dhcp6/dhcp6_srv.h"
+
+using namespace std;
+using namespace isc;
+
+Dhcpv6Srv::Dhcpv6Srv() {
+    cout << "Initialization" << endl;
+}
+
+bool Dhcpv6Srv::run() {
+    while (true) {
+        Pkt6 * pkt;
+
+        pkt = IfaceMgr::instance().receive();
+
+        if (pkt) {
+            Addr6 client = pkt->remoteAddr;
+            cout << "Received " << pkt->dataLen_ << " bytes, echoing back."
+                 << endl;
+            IfaceMgr::instance().send(*pkt);
+            delete pkt;
+        }
+
+        sleep(1);
+
+    }
+
+    return true;
+}

+ 42 - 0
src/bin/dhcp6/dhcp6_srv.h

@@ -0,0 +1,42 @@
+// Copyright (C) 2011  Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#ifndef DHCPV6_SRV_H
+#define DHCPV6_SRV_H
+
+#include <iostream>
+
+#include "dhcp6/addr6.h"
+
+namespace isc {
+    class Dhcpv6Srv {
+    private:
+        // defined private on purpose. We don't want to have more than
+        // one copy
+        Dhcpv6Srv(const Dhcpv6Srv& src);
+        Dhcpv6Srv& operator=(const Dhcpv6Srv& src);
+
+    public:
+        // default constructor
+        Dhcpv6Srv();
+        ~Dhcpv6Srv();
+
+        bool run();
+
+    protected:
+        bool shutdown;
+    };
+};
+
+#endif // DHCP6_SRV_H

+ 468 - 0
src/bin/dhcp6/iface_mgr.cc

@@ -0,0 +1,468 @@
+// Copyright (C) 2011  Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#include <sstream>
+#include <fstream>
+#include <string.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <net/if.h>
+
+#include "addr6.h"
+#include "dhcp6/iface_mgr.h"
+#include "dhcp6/dhcp6.h"
+
+using namespace std;
+using namespace isc;
+
+// IfaceMgr is a singleton implementation
+IfaceMgr * IfaceMgr::instance_ = 0;
+
+void IfaceMgr::instanceCreate() {
+    if (instance_) {
+        // XXX: throw exception here
+        return;
+    }
+    instance_ = new IfaceMgr();
+}
+
+IfaceMgr& IfaceMgr::instance() {
+    if (instance_ == 0)
+        instanceCreate();
+    return *instance_;
+}
+
+
+IfaceMgr::Iface::Iface()
+    : name_(""), ifindex_(0), macLen_(0) {
+    memset(mac_, 0, 20);
+}
+
+IfaceMgr::Iface::Iface(const std::string name, int ifindex)
+    :name_(name), ifindex_(ifindex), macLen_(0) {
+    memset(mac_, 0, 20);
+}
+
+std::string IfaceMgr::Iface::getFullName() const {
+    ostringstream tmp;
+    tmp << name_ << "/" << ifindex_;
+    return tmp.str();
+}
+
+std::string IfaceMgr::Iface::getPlainMac() const {
+    ostringstream tmp;
+    for (int i=0; i<macLen_; i++) {
+        tmp.fill('0');
+        tmp.width(2);
+        tmp << (hex) << (int) mac_[i];
+        if (i<macLen_-1) {
+            tmp << ":";
+        }
+    }
+    return tmp.str();
+}
+
+IfaceMgr::IfaceMgr() {
+
+    control_buf_len_ = CMSG_SPACE(sizeof(struct in6_pktinfo));
+    control_buf_ = (char*) new char[control_buf_len_];
+
+   cout << "IfaceMgr initialization." << endl;
+
+   detectIfaces();
+
+   openSockets();
+}
+
+IfaceMgr::~IfaceMgr() {
+    if (control_buf_) {
+        delete [] control_buf_;
+        control_buf_ = 0;
+        control_buf_len_ = 0;
+    }
+}
+
+void IfaceMgr::detectIfaces() {
+    string ifaceName, linkLocal;
+
+    // XXX: do the actual detection
+
+    cout << "Interface detection is not implemented yet. "
+         << "Reading interfaces.txt file instead." << endl;
+    cout << "Please use format: interface-name link-local-address" << endl;
+
+    ifstream interfaces("interfaces.txt");
+    interfaces >> ifaceName;
+    interfaces >> linkLocal;
+
+    cout << "Detected interface " << ifaceName << "/" << linkLocal << endl;
+
+    Iface iface(ifaceName, if_nametoindex( ifaceName.c_str() ) );
+    Addr6 addr(linkLocal.c_str(), true);
+    iface.addrs_.push_back(addr);
+    ifaces_.push_back(iface);
+    interfaces.close();
+}
+
+bool IfaceMgr::openSockets() {
+    int sock;
+
+    for (IfaceLst::iterator iface=ifaces_.begin();
+         iface!=ifaces_.end();
+         ++iface) {
+
+
+        for (Addr6Lst::iterator addr=iface->addrs_.begin();
+             addr!=iface->addrs_.end();
+             ++addr) {
+
+            sock = openSocket(iface->name_, *addr,
+                              DHCP6_SERVER_PORT, false);
+            if (sock<0) {
+                cout << "Failed to open unicast socket." << endl;
+                return false;
+            }
+            sendsock_ = sock;
+
+            sock = openSocket(iface->name_,
+                              Addr6(ALL_DHCP_RELAY_AGENTS_AND_SERVERS, true),
+                              DHCP6_SERVER_PORT, true);
+            if (sock<0) {
+                cout << "Failed to open multicast socket." << endl;
+                return false;
+            }
+            recvsock_ = sock;
+        }
+    }
+
+    return true;
+}
+
+void IfaceMgr::printIfaces() {
+    for (IfaceLst::const_iterator iface=ifaces_.begin();
+         iface!=ifaces_.end();
+         ++iface) {
+        cout << "Detected interface " << iface->getFullName() << endl;
+        cout << "  " << iface->addrs_.size() << " addr(s):" << endl;
+        for (Addr6Lst::const_iterator addr=iface->addrs_.begin();
+             addr != iface->addrs_.end();
+             ++addr) {
+            cout << "  " << *addr << endl;
+        }
+        cout << "  mac: " << iface->getPlainMac() << endl;
+    }
+}
+
+IfaceMgr::Iface* IfaceMgr::getIface(int ifindex) {
+    for (IfaceLst::iterator iface=ifaces_.begin();
+         iface!=ifaces_.end();
+         ++iface) {
+        if (iface->ifindex_ == ifindex)
+            return &(*iface);
+    }
+
+    return 0; // not found
+}
+
+IfaceMgr::Iface* IfaceMgr::getIface(const std::string &ifname) {
+    for (IfaceLst::iterator iface=ifaces_.begin();
+         iface!=ifaces_.end();
+         ++iface) {
+        if (iface->name_ == ifname)
+            return &(*iface);
+    }
+
+    return 0; // not found
+}
+
+int IfaceMgr::openSocket(const std::string &ifname,
+                         const Addr6 &addr,
+                         int port,
+                         bool mcast) {
+    struct sockaddr_storage name;
+    int name_len;
+    struct sockaddr_in6 *addr6;
+
+    cout << "Creating socket on " << ifname << "/" << addr << "/port=" 
+         << port << endl;
+
+    memset(&name, 0, sizeof(name));
+    addr6 = (struct sockaddr_in6 *)&name;
+    addr6->sin6_family = AF_INET6;
+    addr6->sin6_port = htons(port);
+    addr6->sin6_scope_id = if_nametoindex(ifname.c_str());
+    memcpy(&addr6->sin6_addr,
+           addr.get(),
+           sizeof(addr6->sin6_addr));
+#ifdef HAVE_SA_LEN
+    addr6->sin6_len = sizeof(*addr6);
+#endif
+    name_len = sizeof(*addr6);
+
+    // XXX: use sockcreator once it becomes available
+
+    // make a socket
+    int sock = socket(AF_INET6, SOCK_DGRAM, 0);
+    if (sock < 0) {
+        cout << "Failed to create UDP6 socket." << endl;
+        return -1;
+    }
+
+    /* Set the REUSEADDR option so that we don't fail to start if
+       we're being restarted. */
+    int flag = 1;
+    if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR,
+                   (char *)&flag, sizeof(flag)) < 0) {
+        cout << "Can't set SO_REUSEADDR option on dhcpv6 socket." << endl;
+        return -1;
+    }
+
+    if (bind(sock, (struct sockaddr *)&name, name_len) < 0) {
+        cout << "Failed to bind socket " << sock << " to " << addr.getPlain()
+             << "/port=" << port << endl;
+        return -1;
+    }
+
+#ifdef IPV6_RECVPKTINFO
+    /* RFC3542 - a new way */
+    if (setsockopt(sock, IPPROTO_IPV6, IPV6_RECVPKTINFO,
+                   &flag, sizeof(flag)) != 0) {
+        cout << "setsockopt: IPV6_RECVPKTINFO failed." << endl;
+        return -1;
+    }
+#else
+    /* RFC2292 - an old way */
+    if (setsockopt(sock, IPPROTO_IPV6, IPV6_PKTINFO,
+                   &flag, sizeof(flag)) != 0) {
+        cout << "setsockopt: IPV6_PKTINFO: failed." << endl;
+        return -1;
+    }
+#endif
+
+    // multicast stuff
+
+    if (mcast /*addr.multicast()*/) {
+        // both mcast (ALL_DHCP_RELAY_AGENTS_AND_SERVERS and ALL_DHCP_SERVERS)
+        // are link and site-scoped, so there is no sense to join those them
+        // with global addressed.
+
+        if ( !joinMcast( sock, ifname, 
+                         string(ALL_DHCP_RELAY_AGENTS_AND_SERVERS) ) ) {
+            close(sock);
+            return -1;
+        }
+    }
+
+    cout << "Created socket " << sock << " on " << ifname << "/" << addr 
+         << "/port=" << port << endl;
+
+    return sock;
+}
+
+bool IfaceMgr::joinMcast(int sock, const std::string& ifname,
+                         const std::string & mcast) {
+
+    struct ipv6_mreq mreq;
+
+        if (inet_pton(AF_INET6, mcast.c_str(),
+                      &mreq.ipv6mr_multiaddr) <= 0) {
+            cout << "Failed to convert " << ifname
+                 << " to IPv6 multicast address." << endl;
+            return false;
+        }
+
+        mreq.ipv6mr_interface = if_nametoindex(ifname.c_str());
+        if (setsockopt(sock, IPPROTO_IPV6, IPV6_JOIN_GROUP,
+                       &mreq, sizeof(mreq)) < 0) {
+            cout << "Failed to join " << mcast << " multicast group." << endl;
+            return false;
+        }
+
+        cout << "Joined multicast " << mcast << " group." << endl;
+
+        return true;
+    }
+
+    bool IfaceMgr::send(Pkt6 &pkt) {
+        struct msghdr m;
+        struct iovec v;
+        int result;
+        struct in6_pktinfo *pktinfo;
+        struct cmsghdr *cmsg;
+        memset(control_buf_, 0, control_buf_len_);
+
+        /*
+         * Initialize our message header structure.
+         */
+        memset(&m, 0, sizeof(m));
+
+        /*
+         * Set the target address we're sending to.
+         */
+        sockaddr_in6 to;
+        memset(&to, 0, sizeof(to));
+        to.sin6_family = AF_INET6;
+        to.sin6_port = htons(pkt.remotePort);
+        memcpy(&to.sin6_addr, pkt.remoteAddr.get(), 16);
+        to.sin6_scope_id = pkt.ifindex;
+
+        m.msg_name = &to;
+        m.msg_namelen = sizeof(to);
+
+        /*
+         * Set the data buffer we're sending. (Using this wacky
+         * "scatter-gather" stuff... we only have a single chunk
+         * of data to send, so we declare a single vector entry.)
+         */
+        v.iov_base = (char *) pkt.data_;
+        v.iov_len = pkt.dataLen_;
+        m.msg_iov = &v;
+        m.msg_iovlen = 1;
+
+        /*
+         * Setting the interface is a bit more involved.
+         *
+         * We have to create a "control message", and set that to
+         * define the IPv6 packet information. We could set the
+         * source address if we wanted, but we can safely let the
+         * kernel decide what that should be.
+         */
+        m.msg_control = control_buf_;
+        m.msg_controllen = control_buf_len_;
+        cmsg = CMSG_FIRSTHDR(&m);
+        cmsg->cmsg_level = IPPROTO_IPV6;
+        cmsg->cmsg_type = IPV6_PKTINFO;
+        cmsg->cmsg_len = CMSG_LEN(sizeof(*pktinfo));
+        pktinfo = (struct in6_pktinfo *)CMSG_DATA(cmsg);
+        memset(pktinfo, 0, sizeof(*pktinfo));
+        pktinfo->ipi6_ifindex = pkt.ifindex;
+        m.msg_controllen = cmsg->cmsg_len;
+
+        result = sendmsg(sendsock_, &m, 0);
+        if (result < 0) {
+            cout << "Send packet failed." << endl;
+        }
+        cout << "Sent " << result << " bytes." << endl;
+
+        cout << "Sent " << pkt.dataLen_ << " bytes over "
+             << pkt.iface << "/" << pkt.ifindex << " interface: "
+             << " dst=" << pkt.remoteAddr << ", src=" << pkt.localAddr
+             << endl;
+
+        return result;
+    }
+
+    Pkt6 * IfaceMgr::receive() {
+        struct msghdr m;
+        struct iovec v;
+        int result;
+        struct cmsghdr *cmsg;
+        struct in6_pktinfo *pktinfo;
+        int found_pktinfo;
+        struct sockaddr_in6 from;
+        struct in6_addr to_addr;
+
+        Pkt6 * pkt = new Pkt6(1500);
+
+        memset(control_buf_, 0, control_buf_len_);
+
+        memset(&from, 0, sizeof(from));
+        memset(&to_addr, 0, sizeof(to_addr));
+
+        /*
+         * Initialize our message header structure.
+         */
+        memset(&m, 0, sizeof(m));
+
+        /*
+         * Point so we can get the from address.
+         */
+        m.msg_name = &from;
+        m.msg_namelen = sizeof(from);
+
+        /*
+         * Set the data buffer we're receiving. (Using this wacky
+         * "scatter-gather" stuff... but we that doesn't really make
+         * sense for us, so we use a single vector entry.)
+         */
+        v.iov_base = pkt->data_;
+        v.iov_len = pkt->dataLen_;
+        m.msg_iov = &v;
+        m.msg_iovlen = 1;
+
+        /*
+         * Getting the interface is a bit more involved.
+         *
+         * We set up some space for a "control message". We have
+         * previously asked the kernel to give us packet
+         * information (when we initialized the interface), so we
+         * should get the destination address from that.
+         */
+        m.msg_control = control_buf_;
+        m.msg_controllen = control_buf_len_;
+
+        result = recvmsg(recvsock_, &m, 0);
+
+        if (result >= 0) {
+            /*
+             * If we did read successfully, then we need to loop
+             * through the control messages we received and
+             * find the one with our destination address.
+             *
+             * We also keep a flag to see if we found it. If we
+             * didn't, then we consider this to be an error.
+             */
+            found_pktinfo = 0;
+            cmsg = CMSG_FIRSTHDR(&m);
+            while (cmsg != NULL) {
+                if ((cmsg->cmsg_level == IPPROTO_IPV6) &&
+                    (cmsg->cmsg_type == IPV6_PKTINFO)) {
+                    pktinfo = (struct in6_pktinfo *)CMSG_DATA(cmsg);
+                    to_addr = pktinfo->ipi6_addr;
+                    pkt->ifindex = pktinfo->ipi6_ifindex;
+                    found_pktinfo = 1;
+                }
+                cmsg = CMSG_NXTHDR(&m, cmsg);
+            }
+            if (!found_pktinfo) {
+                cout << "Unable to find pktinfo" << endl;
+                delete pkt;
+                return 0;
+            }
+        } else {
+            cout << "Failed to receive data." << endl;
+
+            delete pkt;
+            return 0;
+        }
+
+        pkt->localAddr = Addr6(&to_addr);
+        pkt->remoteAddr = Addr6(&from);
+        pkt->remotePort = ntohs(from.sin6_port);
+
+        Iface * received = getIface(pkt->ifindex);
+        if (received) {
+            pkt->iface = received->name_;
+        }
+
+        pkt->dataLen_ = result;
+
+        cout << "Received " << pkt->dataLen_ << " bytes over "
+             << pkt->iface << "/" << pkt->ifindex << " interface: "
+             << " src=" << pkt->remoteAddr << ", dst=" << pkt->localAddr
+             << endl;
+
+        return pkt;
+
+    }

+ 87 - 0
src/bin/dhcp6/iface_mgr.h

@@ -0,0 +1,87 @@
+// Copyright (C) 2011  Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#ifndef IFACE_MGR_H
+#define IFACE_MGR_H
+
+#include <list>
+#include "dhcp6/addr6.h"
+#include "dhcp6/pkt6.h"
+
+namespace isc {
+
+    /**
+     * IfaceMgr is an interface manager class that detects available network
+     * interfaces, configured addresses, link-local addresses, and provides
+     * API for using sockets.
+     *
+     */
+    class IfaceMgr {
+    public:
+        struct Iface { // XXX: could be a class as well
+            std::string name_;
+            int ifindex_;
+            Addr6Lst addrs_;
+            char mac_[20]; //
+            int macLen_;
+
+            Iface();
+            Iface(const std::string name, int ifindex);
+            std::string getFullName() const;
+            std::string getPlainMac() const;
+
+            // next field is not needed, let's keep it in cointainers
+        };
+        typedef std::list<Iface> IfaceLst;
+
+    private:
+        IfaceMgr(); // don't create IfaceMgr directly, use instance() method
+        ~IfaceMgr();
+    public:
+        static IfaceMgr& instance();
+        static void instanceCreate();
+
+        Iface * getIface(int ifindex);
+        Iface * getIface(const std::string &ifname);
+
+        bool openSockets();
+        void printIfaces();
+
+        int openSocket(const std::string &ifname,
+                       const Addr6 &addr,
+                       int port, bool multicast);
+        bool joinMcast(int sock, const std::string &ifname,
+                       const std::string& mcast);
+
+        bool send(Pkt6 &pkt);
+        Pkt6 * receive();
+
+    protected:
+        void detectIfaces();
+
+        // XXX: having 2 maps (ifindex->iface and ifname->iface would)
+        //      probably be better for performance reasons
+        IfaceLst ifaces_;
+    private:
+        static IfaceMgr * instance_;
+
+        int recvsock_; // XXX: should be fd_set eventually, but we 2 sockets
+        int sendsock_; // will do for until next release
+
+        char * control_buf_;
+        int control_buf_len_;
+    };
+};
+
+#endif

+ 10 - 0
src/bin/dhcp6/interfaces.txt

@@ -0,0 +1,10 @@
+eth0 fe80::21e:8cff:fe9b:7349
+
+#
+# only first line is read.
+# please use following format:
+# interface-name link-local-ipv6-address
+#
+# This file will become obsolete once proper interface detection 
+# is implemented.
+#

+ 8 - 6
src/bin/dhcp6/main.cc

@@ -33,7 +33,7 @@
 #include <log/dummylog.h>
 
 #include <dhcp6/spec_config.h>
-
+#include "dhcp6/dhcp6_srv.h"
 
 using namespace std;
 using namespace isc::util;
@@ -42,6 +42,8 @@ using namespace isc::cc;
 using namespace isc::config;
 using namespace isc::util;
 
+using namespace isc;
+
 namespace {
 
 bool verbose_mode = false;
@@ -108,15 +110,15 @@ main(int argc, char* argv[]) {
         // auth_server->setVerbose(verbose_mode);
         cout << "[b10-dhcp6] Initiating DHCPv6 operation." << endl;
 
+        Dhcpv6Srv *srv = new Dhcpv6Srv();
+
+        //srv->init();
+        srv->run();
+
     } catch (const std::exception& ex) {
         cerr << "[b10-dhcp6] Server failed: " << ex.what() << endl;
         ret = 1;
     }
 
-    while (true) {
-            sleep(10);
-            cout << "[b10-dhcp6] I'm alive." << endl;
-    }
-
     return (ret);
 }

+ 38 - 0
src/bin/dhcp6/pkt6.cc

@@ -0,0 +1,38 @@
+// Copyright (C) 2011  Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+
+#include "dhcp6/dhcp6.h"
+#include "dhcp6/pkt6.h"
+
+namespace isc {
+
+    Pkt6::Pkt6(char * data, int dataLen) {
+        data_ = data;
+        dataLen_ = dataLen;
+    }
+
+    Pkt6::Pkt6(int dataLen) {
+        data_ = new char[dataLen];
+        dataLen_ = dataLen;
+    }
+
+    Pkt6::~Pkt6() {
+        if (data_) {
+            delete [] data_;
+        }
+
+    }
+
+};

+ 48 - 0
src/bin/dhcp6/pkt6.h

@@ -0,0 +1,48 @@
+// Copyright (C) 2011  Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#ifndef PKT6_H
+#define PKT6_H
+
+#include <iostream>
+#include "dhcp6/addr6.h"
+
+namespace isc {
+
+    class Pkt6 {
+    public:
+        Pkt6(char * data, int dataLen);
+        Pkt6(int len);
+        ~Pkt6();
+
+        // XXX: probably need getter/setter wrappers
+        //      and hide fields as protected
+        char * data_;
+        int dataLen_;
+
+        Addr6 localAddr;
+        Addr6 remoteAddr;
+
+        std::string iface;
+        int ifindex;
+
+        int localPort;
+        int remotePort;
+
+        // XXX: add *a lot* here
+
+    };
+}
+
+#endif