iface_mgr.cc 22.8 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// 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>

21
22
23
#include <dhcp/dhcp6.h>
#include <dhcp6/iface_mgr.h>
#include <exceptions/exceptions.h>
24
25
26

using namespace std;
using namespace isc;
27
using namespace isc::asiolink;
28
using namespace isc::dhcp;
29

30
31
namespace isc {

32
/// IfaceMgr is a singleton implementation
33
IfaceMgr* IfaceMgr::instance_ = 0;
34

35
36
void
IfaceMgr::instanceCreate() {
37
    if (instance_) {
38
        // no need to do anything. Instance is already created.
39
        // Who called it again anyway? Uh oh. Had to be us, as
40
        // this is private method.
41
42
43
44
45
        return;
    }
    instance_ = new IfaceMgr();
}

46
47
IfaceMgr&
IfaceMgr::instance() {
48
    if (instance_ == 0) {
49
        instanceCreate();
50
    }
51
    return (*instance_);
52
53
}

54
55
IfaceMgr::Iface::Iface(const std::string& name, int ifindex)
    :name_(name), ifindex_(ifindex), mac_len_(0) {
56
57

    memset(mac_, 0, sizeof(mac_));
58
59
}

60
61
std::string
IfaceMgr::Iface::getFullName() const {
62
63
    ostringstream tmp;
    tmp << name_ << "/" << ifindex_;
64
    return (tmp.str());
65
66
}

67
68
std::string
IfaceMgr::Iface::getPlainMac() const {
69
    ostringstream tmp;
70
71
    tmp.fill('0');
    tmp << hex;
72
    for (int i = 0; i < mac_len_; i++) {
73
        tmp.width(2);
74
        tmp << mac_[i];
75
        if (i < mac_len_-1) {
76
77
78
            tmp << ":";
        }
    }
79
    return (tmp.str());
80
81
}

82
83
84
85
86
87
88
89
90
91
92
bool IfaceMgr::Iface::delAddress(const isc::asiolink::IOAddress& addr) {
    for (AddressCollection::iterator a = addrs_.begin();
         a!=addrs_.end(); ++a) {
        if (*a==addr) {
            addrs_.erase(a);
            return (true);
        }
    }
    return (false);
}

93
94
95
96
97
98
99
100
101
102
103
104
105
bool IfaceMgr::Iface::delSocket(uint16_t sockfd) {
    list<SocketInfo>::iterator sock = sockets_.begin();
    while (sock!=sockets_.end()) {
        if (sock->sockfd_ == sockfd) {
            close(sockfd);
            sockets_.erase(sock);
            return (true); //socket found
        }
        ++sock;
    }
    return (false); // socket not found
}

106
107
108
109
IfaceMgr::IfaceMgr()
    :control_buf_len_(CMSG_SPACE(sizeof(struct in6_pktinfo))),
     control_buf_(new char[control_buf_len_])
{
110

111
    cout << "IfaceMgr initialization." << endl;
112

113
    try {
114
115
116
        // required for sending/receiving packets
        // let's keep it in front, just in case someone
        // wants to send anything during initialization
117
118

        // control_buf_ = boost::scoped_array<char>();
119

120
        detectIfaces();
121

122
    } catch (const std::exception& ex) {
123
124
125
126
127
128
129
130
        cout << "IfaceMgr creation failed:" << ex.what() << endl;

        // TODO Uncomment this (or call LOG_FATAL) once
        // interface detection is implemented. Otherwise
        // it is not possible to run tests in a portable
        // way (see detectIfaces() method).
        // throw ex;
    }
131
132
133
}

IfaceMgr::~IfaceMgr() {
134
    // control_buf_ is deleted automatically (scoped_ptr)
135
    control_buf_len_ = 0;
136
137
}

138
139
void
IfaceMgr::detectIfaces() {
140
141
    string ifaceName, linkLocal;

142
143
    // TODO do the actual detection. Currently interface detection is faked
    //      by reading a text file.
144
145
146
147
148

    cout << "Interface detection is not implemented yet. "
         << "Reading interfaces.txt file instead." << endl;
    cout << "Please use format: interface-name link-local-address" << endl;

149
150
    try {
        ifstream interfaces("interfaces.txt");
151

152
153
154
155
156
157
158
159
160
161
        if (!interfaces.good()) {
            cout << "Failed to read interfaces.txt file." << endl;
            isc_throw(Unexpected, "Failed to read interfaces.txt");
        }
        interfaces >> ifaceName;
        interfaces >> linkLocal;

        cout << "Detected interface " << ifaceName << "/" << linkLocal << endl;

        Iface iface(ifaceName, if_nametoindex( ifaceName.c_str() ) );
162
        IOAddress addr(linkLocal);
163
164
        iface.addAddress(addr);
        addInterface(iface);
165
        interfaces.close();
166
    } catch (const std::exception& ex) {
167
168
169
170
171
        // TODO: deallocate whatever memory we used
        // not that important, since this function is going to be
        // thrown away as soon as we get proper interface detection
        // implemented

172
173
174
175
        // TODO Do LOG_FATAL here
        std::cerr << "Interface detection failed." << std::endl;
        throw ex;
    }
176
177
}

178
void
179
IfaceMgr::openSockets() {
180
    int sock1, sock2;
181

182
    for (IfaceCollection::iterator iface=ifaces_.begin();
183
184
185
         iface!=ifaces_.end();
         ++iface) {

186
187
188
189
        AddressCollection addrs = iface->getAddresses();

        for (AddressCollection::iterator addr= addrs.begin();
             addr != addrs.end();
190
191
             ++addr) {

192
193
            sock1 = openSocket(iface->getName(), *addr, DHCP6_SERVER_PORT);
            if (sock1<0) {
194
195
                isc_throw(Unexpected, "Failed to open unicast socket on "
                          << " interface " << iface->getFullName());
196
197
            }

198
199
200
201
202
203
204
205
206
207
208
209
            if ( !joinMcast(sock1, iface->getName(),
                             string(ALL_DHCP_RELAY_AGENTS_AND_SERVERS) ) ) {
                close(sock1);
                isc_throw(Unexpected, "Failed to join " << ALL_DHCP_RELAY_AGENTS_AND_SERVERS
                          << " multicast group.");
            }

            // this doesn't work too well on NetBSD
            sock2 = openSocket(iface->getName(),
                               IOAddress(ALL_DHCP_RELAY_AGENTS_AND_SERVERS),
                               DHCP6_SERVER_PORT);
            if (sock2<0) {
210
211
                isc_throw(Unexpected, "Failed to open multicast socket on "
                          << " interface " << iface->getFullName());
212
                iface->delSocket(sock1); // delete previously opened socket
213
214
215
216
217
            }
        }
    }
}

218
void
219
IfaceMgr::printIfaces(std::ostream& out /*= std::cout*/) {
220
    for (IfaceCollection::const_iterator iface=ifaces_.begin();
221
222
         iface!=ifaces_.end();
         ++iface) {
223
        out << "Detected interface " << iface->getFullName() << endl;
224
225
226
227
228
        out << "  " << iface->getAddresses().size() << " addr(s):" << endl;
        const AddressCollection addrs = iface->getAddresses();

        for (AddressCollection::const_iterator addr = addrs.begin();
             addr != addrs.end();
229
             ++addr) {
230
            out << "  " << addr->toText() << endl;
231
        }
232
        out << "  mac: " << iface->getPlainMac() << endl;
233
234
235
    }
}

236
237
IfaceMgr::Iface*
IfaceMgr::getIface(int ifindex) {
238
    for (IfaceCollection::iterator iface=ifaces_.begin();
239
240
         iface!=ifaces_.end();
         ++iface) {
241
        if (iface->getIndex() == ifindex)
242
            return (&(*iface));
243
244
    }

245
    return (NULL); // not found
246
247
}

248
IfaceMgr::Iface*
249
IfaceMgr::getIface(const std::string& ifname) {
250
    for (IfaceCollection::iterator iface=ifaces_.begin();
251
252
         iface!=ifaces_.end();
         ++iface) {
253
        if (iface->getName() == ifname)
254
            return (&(*iface));
255
256
    }

257
    return (NULL); // not found
258
259
}

260
uint16_t
261
IfaceMgr::openSocket(const std::string& ifname,
262
                     const IOAddress& addr,
263
                     int port) {
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
    Iface* iface = getIface(ifname);
    if (!iface) {
        isc_throw(BadValue, "There is no " << ifname << " interface present.");
    }
    switch (addr.getFamily()) {
    case AF_INET:
        return openSocket4(*iface, addr, port);
    case AF_INET6:
        return openSocket6(*iface, addr, port);
    default:
        isc_throw(BadValue, "Failed to detect family of address: "
                  << addr.toText());
    }
}

279
uint16_t
280
IfaceMgr::openSocket4(Iface& iface, const IOAddress& addr, int port) {
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325

    cout << "Creating UDP4 socket on " << iface.getFullName()
         << " " << addr.toText() << "/port=" << port << endl;

    struct sockaddr_in addr4;
    memset(&addr4, 0, sizeof(sockaddr));
    addr4.sin_family = AF_INET;
    addr4.sin_port = htons(port);
    memcpy(&addr4.sin_addr, addr.getAddress().to_v4().to_bytes().data(),
           sizeof(addr4.sin_addr));

    int sock = socket(AF_INET, SOCK_DGRAM, 0);
    if (sock < 0) {
        isc_throw(Unexpected, "Failed to create UDP6 socket.");
    }

    if (bind(sock, (struct sockaddr *)&addr4, sizeof(addr4)) < 0) {
        close(sock);
        isc_throw(Unexpected, "Failed to bind socket " << sock << " to " << addr.toText()
                  << "/port=" << port);
    }

#if defined(SO_BINDTODEVICE)
#if 0
    /// For some reason that doesn't work. It's not a big deal as this is
    /// Linux only feature. We can use IP_PKTINFO to check that we received
    /// packet over proper interface.

    // Bind this socket to this interface.
    const char* ifname = iface.getName().c_str();
    int len = strlen(ifname);
    if (setsockopt(sock, SOL_SOCKET, SO_BINDTODEVICE,
                   ifname, len) < 0) {
        isc_throw(Unexpected, "setsockopt: SO_BINDTODEVICE failed.");
    }
#endif
#endif

    int flag = 1;
#ifdef IP_RECVPKTINFO
    if (setsockopt(sock, IPPROTO_IP, IP_RECVPKTINFO,
                   &flag, sizeof(flag)) != 0) {
        close(sock);
        isc_throw(Unexpected, "setsockopt: IP_RECVPKTINFO failed.")
    }
326
#elif defined(IP_PKTINFO)
327
328
329
330
331
332
    /* RFC2292 - an old way */
    if (setsockopt(sock, IPPROTO_IP, IP_PKTINFO,
                   &flag, sizeof(flag)) != 0) {
        close(sock);
        isc_throw(Unexpected, "setsockopt: IP_PKTINFO: failed.");
    }
333
334
335
#else
    // "Neither IP_RECVPKTINFO nor IP_PKTINFO defined. Cannot continue"
    flag = 1; // just to avoid compilation warnings about unused flag variable
336
337
338
339
340
341
#endif


    cout << "Created socket " << sock << " on " << iface.getName() << "/" <<
        addr.toText() << "/port=" << port << endl;

342
343
344
    SocketInfo info(sock, addr, port);
    iface.addSocket(info);

345
    return (sock);
346
347
}

348
uint16_t
349
IfaceMgr::openSocket6(Iface& iface, const IOAddress& addr, int port) {
350

351
352
    cout << "Creating UDP6 socket on " << iface.getFullName()
         << " " << addr.toText() << "/port=" << port << endl;
353

354
    struct sockaddr_in6 addr6;
355
356
357
    memset(&addr6, 0, sizeof(addr6));
    addr6.sin6_family = AF_INET6;
    addr6.sin6_port = htons(port);
358
    addr6.sin6_scope_id = if_nametoindex(iface.getName().c_str());
359

360
    memcpy(&addr6.sin6_addr,
361
           addr.getAddress().to_v6().to_bytes().data(),
362
           sizeof(addr6.sin6_addr));
363
#ifdef HAVE_SA_LEN
364
    addr6->sin6_len = sizeof(addr6);
365
366
#endif

367
    // TODO: use sockcreator once it becomes available
368
369
370
371

    // make a socket
    int sock = socket(AF_INET6, SOCK_DGRAM, 0);
    if (sock < 0) {
372
        isc_throw(Unexpected, "Failed to create UDP6 socket.");
373
374
375
376
377
378
379
    }

    /* 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) {
380
        close(sock);
381
        isc_throw(Unexpected, "Can't set SO_REUSEADDR option on dhcpv6 socket.");
382
383
    }

384
    if (bind(sock, (struct sockaddr *)&addr6, sizeof(addr6)) < 0) {
385
        close(sock);
386
387
        isc_throw(Unexpected, "Failed to bind socket " << sock << " to " << addr.toText()
                  << "/port=" << port);
388
389
390
391
392
    }
#ifdef IPV6_RECVPKTINFO
    /* RFC3542 - a new way */
    if (setsockopt(sock, IPPROTO_IPV6, IPV6_RECVPKTINFO,
                   &flag, sizeof(flag)) != 0) {
393
        close(sock);
394
        isc_throw(Unexpected, "setsockopt: IPV6_RECVPKTINFO failed.");
395
396
397
398
399
    }
#else
    /* RFC2292 - an old way */
    if (setsockopt(sock, IPPROTO_IPV6, IPV6_PKTINFO,
                   &flag, sizeof(flag)) != 0) {
400
        close(sock);
401
        isc_throw(Unexpected, "setsockopt: IPV6_PKTINFO: failed.");
402
403
404
405
    }
#endif

    // multicast stuff
406
    if (addr.getAddress().to_v6().is_multicast()) {
407
        // both mcast (ALL_DHCP_RELAY_AGENTS_AND_SERVERS and ALL_DHCP_SERVERS)
408
409
        // are link and site-scoped, so there is no sense to join those groups
        // with global addresses.
410

411
        if ( !joinMcast( sock, iface.getName(),
412
413
                         string(ALL_DHCP_RELAY_AGENTS_AND_SERVERS) ) ) {
            close(sock);
414
415
            isc_throw(Unexpected, "Failed to join " << ALL_DHCP_RELAY_AGENTS_AND_SERVERS
                      << " multicast group.");
416
417
418
        }
    }

419
    cout << "Created socket " << sock << " on " << iface.getName() << "/" <<
420
        addr.toText() << "/port=" << port << endl;
421

422
423
    SocketInfo info(sock, addr, port);
    iface.addSocket(info);
424

425
    return (sock);
426
427
}

428
429
430
bool
IfaceMgr::joinMcast(int sock, const std::string& ifname,
const std::string & mcast) {
431
432
433

    struct ipv6_mreq mreq;

434
435
436
437
438
    if (inet_pton(AF_INET6, mcast.c_str(),
                  &mreq.ipv6mr_multiaddr) <= 0) {
        cout << "Failed to convert " << ifname
             << " to IPv6 multicast address." << endl;
        return (false);
439
440
    }

441
442
443
444
445
    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);
446
447
    }

448
    cout << "Joined multicast " << mcast << " group." << endl;
449

450
451
    return (true);
}
452

453
bool
454
IfaceMgr::send(boost::shared_ptr<Pkt6>& pkt) {
455
456
457
458
459
    struct msghdr m;
    struct iovec v;
    int result;
    struct in6_pktinfo *pktinfo;
    struct cmsghdr *cmsg;
460
461
462
463
464
465
466

    Iface* iface = getIface(pkt->iface_);
    if (!iface) {
        isc_throw(BadValue, "Unable to send Pkt6. Invalid interface ("
                  << pkt->iface_ << ") specified.");
    }

467
    memset(&control_buf_[0], 0, control_buf_len_);
468
469
470
471
472
473
474
475
476
477
478
479

    /*
     * 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;
480
    to.sin6_port = htons(pkt->remote_port_);
481
    memcpy(&to.sin6_addr,
482
           pkt->remote_addr_.getAddress().to_v6().to_bytes().data(),
483
           16);
484
    to.sin6_scope_id = pkt->ifindex_;
485
486
487
488
489
490
491
492
493

    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.)
     */
494
495
    v.iov_base = (char *) &pkt->data_[0];
    v.iov_len = pkt->data_len_;
496
497
498
499
500
501
502
503
504
505
506
    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.
     */
507
    m.msg_control = &control_buf_[0];
508
509
510
511
512
513
514
    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));
515
    pktinfo->ipi6_ifindex = pkt->ifindex_;
516
517
    m.msg_controllen = cmsg->cmsg_len;

518
    result = sendmsg(getSocket(*pkt), &m, 0);
519
520
521
    if (result < 0) {
        cout << "Send packet failed." << endl;
    }
522
523
    cout << "Sent " << pkt->data_len_ << " bytes over socket " << getSocket(*pkt)
         << " on " << iface->getFullName() << " interface: "
524
525
         << " dst=" << pkt->remote_addr_.toText()
         << ", src=" << pkt->local_addr_.toText()
526
         << endl;
527

528
529
    return (result);
}
530

531
532
533
534
535
536
boost::shared_ptr<Pkt4>
IfaceMgr::receive4() {
    // TODO: To be implemented
    return (boost::shared_ptr<Pkt4>()); // NULL
}

537
boost::shared_ptr<Pkt6>
538
IfaceMgr::receive6() {
539
540
541
542
543
544
545
    struct msghdr m;
    struct iovec v;
    int result;
    struct cmsghdr* cmsg;
    struct in6_pktinfo* pktinfo;
    struct sockaddr_in6 from;
    struct in6_addr to_addr;
546
    boost::shared_ptr<Pkt6> pkt;
547
    char addr_str[INET6_ADDRSTRLEN];
548
549

    try {
550
551
552
553
554
555
556
        // RFC3315 states that server responses may be
        // fragmented if they are over MTU. There is no
        // text whether client's packets may be larger
        // than 1500. Nevertheless to be on the safe side
        // we use larger buffer. This buffer limit is checked
        // during reception (see iov_len below), so we are
        // safe
557
        pkt = boost::shared_ptr<Pkt6>(new Pkt6(65536));
558
    } catch (const std::exception& ex) {
559
        cout << "Failed to create new packet." << endl;
560
        return (boost::shared_ptr<Pkt6>()); // NULL
561
    }
562

563
    memset(&control_buf_[0], 0, control_buf_len_);
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583

    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.)
     */
584
    v.iov_base = (void*)&pkt->data_[0];
585
586
587
588
589
590
591
592
593
594
595
596
    v.iov_len = pkt->data_len_;
    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.
     */
597
    m.msg_control = &control_buf_[0];
598
599
    m.msg_controllen = control_buf_len_;

600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
    /// TODO: Need to move to select() and pool over
    /// all available sockets. For now, we just take the
    /// first interface and use first socket from it.
    IfaceCollection::const_iterator iface = ifaces_.begin();
    if (iface == ifaces_.end()) {
        isc_throw(Unexpected, "No interfaces detected. Can't receive anything.");
    }
    SocketCollection::const_iterator s = iface->sockets_.begin();
    const SocketInfo* candidate = 0;
    while (s != iface->sockets_.end()) {
        if (s->addr_.getAddress().to_v6().is_multicast()) {
            candidate = &(*s);
            break;
        }
        if (!candidate) {
            candidate = &(*s); // it's not multicast, but it's better than none
        }
        ++s;
    }
    if (!candidate) {
        isc_throw(Unexpected, "Interface " << iface->getFullName()
                  << " does not have any sockets open.");
    }

    cout << "Trying to receive over socket " << candidate->sockfd_ << " bound to "
         << candidate->addr_.toText() << "/port=" << candidate->port_ << " on "
         << iface->getFullName() << endl;
    result = recvmsg(candidate->sockfd_, &m, 0);
628
629

    if (result >= 0) {
630
        /*
631
632
633
         * If we did read successfully, then we need to loop
         * through the control messages we received and
         * find the one with our destination address.
634
         *
635
636
         * We also keep a flag to see if we found it. If we
         * didn't, then we consider this to be an error.
637
         */
638
639
640
641
642
643
644
645
646
        int 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;
647
            }
648
649
650
651
            cmsg = CMSG_NXTHDR(&m, cmsg);
        }
        if (!found_pktinfo) {
            cout << "Unable to find pktinfo" << endl;
652
            return (boost::shared_ptr<Pkt6>()); // NULL
653
        }
654
655
    } else {
        cout << "Failed to receive data." << endl;
656
        return (boost::shared_ptr<Pkt6>()); // NULL
657
    }
658

659
    // That's ugly.
660
    // TODO add IOAddress constructor that will take struct in6_addr*
661
    // TODO: there's from_bytes() method added in IOAddress. Use it!
662
663
664
    inet_ntop(AF_INET6, &to_addr, addr_str,INET6_ADDRSTRLEN);
    pkt->local_addr_ = IOAddress(string(addr_str));

665
    // TODO: there's from_bytes() method added in IOAddress. Use it!
666
667
668
    inet_ntop(AF_INET6, &from.sin6_addr, addr_str, INET6_ADDRSTRLEN);
    pkt->remote_addr_ = IOAddress(string(addr_str));

669
670
671
672
    pkt->remote_port_ = ntohs(from.sin6_port);

    Iface* received = getIface(pkt->ifindex_);
    if (received) {
673
        pkt->iface_ = received->getName();
674
675
    } else {
        cout << "Received packet over unknown interface (ifindex="
676
             << pkt->ifindex_ << ")." << endl;
677
        return (boost::shared_ptr<Pkt6>()); // NULL
678
    }
679

680
    pkt->data_len_ = result;
681

682
683
684
    // TODO Move this to LOG_DEBUG
    cout << "Received " << pkt->data_len_ << " bytes over "
         << pkt->iface_ << "/" << pkt->ifindex_ << " interface: "
685
686
         << " src=" << pkt->remote_addr_.toText()
         << ", dst=" << pkt->local_addr_.toText()
687
         << endl;
688

689
690
    return (pkt);
}
691

692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
uint16_t
IfaceMgr::getSocket(isc::dhcp::Pkt6 const& pkt) {
    Iface* iface = getIface(pkt.iface_);
    if (!iface) {
        isc_throw(BadValue, "Tried to find socket for non-existent interface "
                  << pkt.iface_);
    }

    SocketCollection::const_iterator s;
    for (s = iface->sockets_.begin(); s != iface->sockets_.end(); ++s) {
        if (s->family_ != AF_INET6) {
            // don't use IPv4 sockets
            continue;
        }
        if (s->addr_.getAddress().to_v6().is_multicast()) {
            // don't use IPv6 sockets bound to multicast address
            continue;
        }
        /// TODO: Add more checks here later. If remote address is
        /// not link-local, we can't use link local bound socket
        /// to send data.

        return (s->sockfd_);
    }

    isc_throw(Unexpected, "Interface " << iface->getFullName()
              << " does not have any suitable IPv6 sockets open.");
}

uint16_t
IfaceMgr::getSocket(isc::dhcp::Pkt4 const& pkt) {
    Iface* iface = getIface(pkt.getIface());
    if (!iface) {
        isc_throw(BadValue, "Tried to find socket for non-existent interface "
                  << pkt.getIface());
    }

    SocketCollection::const_iterator s;
    for (s = iface->sockets_.begin(); s != iface->sockets_.end(); ++s) {
        if (s->family_ != AF_INET) {
            // don't use IPv4 sockets
            continue;
        }
        /// TODO: Add more checks here later. If remote address is
        /// not link-local, we can't use link local bound socket
        /// to send data.

        return (s->sockfd_);
    }

    isc_throw(Unexpected, "Interface " << iface->getFullName()
              << " does not have any suitable IPv4 sockets open.");
}



748
}