iface_mgr.cc 22.7 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
bool IfaceMgr::Iface::delAddress(const isc::asiolink::IOAddress& addr) {
83
84
85
86
87
88
89
90
91
92
93

    // Let's delete all addresses that match. It really shouldn't matter
    // if we delete first or all, as the OS should allow to add a single
    // address to an interface only once. If OS allows multiple instances
    // of the same address added, we are in deep problems anyway.
    size_t size = addrs_.size();
    addrs_.erase(remove(addrs_.begin(), addrs_.end(), addr), addrs_.end());
    if (addrs_.size() < size) {
        return (true);
    } else {
        return (false);
94
95
96
    }
}

97
98
99
100
101
102
103
104
105
106
107
108
109
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
}

110
111
112
113
IfaceMgr::IfaceMgr()
    :control_buf_len_(CMSG_SPACE(sizeof(struct in6_pktinfo))),
     control_buf_(new char[control_buf_len_])
{
114

115
    cout << "IfaceMgr initialization." << endl;
116

117
    try {
118
119
120
        // required for sending/receiving packets
        // let's keep it in front, just in case someone
        // wants to send anything during initialization
121
122

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

124
        detectIfaces();
125

126
    } catch (const std::exception& ex) {
127
128
129
130
131
132
133
134
        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;
    }
135
136
}

137
void IfaceMgr::closeSockets() {
138
139
140
141
142
143
144
145
146
147
148
    for (IfaceCollection::iterator iface = ifaces_.begin();
         iface != ifaces_.end(); ++iface) {

        for (SocketCollection::iterator sock = iface->sockets_.begin();
             sock != iface->sockets_.end(); ++sock) {
            cout << "Closing socket " << sock->sockfd_ << endl;
            close(sock->sockfd_);
        }
        iface->sockets_.clear();
    }

149
150
151
152
153
}

IfaceMgr::~IfaceMgr() {
    closeSockets();

154
    // control_buf_ is deleted automatically (scoped_ptr)
155
    control_buf_len_ = 0;
156
157
}

158
159
void
IfaceMgr::detectIfaces() {
160
161
    string ifaceName, linkLocal;

162
163
    // TODO do the actual detection. Currently interface detection is faked
    //      by reading a text file.
164
165
166
167
168

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

169
170
    try {
        ifstream interfaces("interfaces.txt");
171

172
173
174
175
176
177
178
179
180
181
        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() ) );
182
        IOAddress addr(linkLocal);
183
184
        iface.addAddress(addr);
        addInterface(iface);
185
        interfaces.close();
186
    } catch (const std::exception& ex) {
187
188
189
190
191
        // 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

192
193
194
195
        // TODO Do LOG_FATAL here
        std::cerr << "Interface detection failed." << std::endl;
        throw ex;
    }
196
197
}

198
void
Tomek Mrugalski's avatar
Tomek Mrugalski committed
199
IfaceMgr::openSockets(uint16_t port) {
200
    int sock1, sock2;
201

Tomek Mrugalski's avatar
Tomek Mrugalski committed
202
203
    for (IfaceCollection::iterator iface = ifaces_.begin();
         iface != ifaces_.end(); ++iface) {
204

205
206
        AddressCollection addrs = iface->getAddresses();

Tomek Mrugalski's avatar
Tomek Mrugalski committed
207
        for (AddressCollection::iterator addr = addrs.begin();
208
             addr != addrs.end();
209
210
             ++addr) {

Tomek Mrugalski's avatar
Tomek Mrugalski committed
211
212
            sock1 = openSocket(iface->getName(), *addr, port);
            if (sock1 < 0) {
213
214
                isc_throw(Unexpected, "Failed to open unicast socket on "
                          << " interface " << iface->getFullName());
215
216
            }

217
218
219
220
221
222
223
224
225
226
            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),
Tomek Mrugalski's avatar
Tomek Mrugalski committed
227
228
                               port);
            if (sock2 < 0) {
229
230
                isc_throw(Unexpected, "Failed to open multicast socket on "
                          << " interface " << iface->getFullName());
231
                iface->delSocket(sock1); // delete previously opened socket
232
233
234
235
236
            }
        }
    }
}

237
void
238
IfaceMgr::printIfaces(std::ostream& out /*= std::cout*/) {
Tomek Mrugalski's avatar
Tomek Mrugalski committed
239
240
    for (IfaceCollection::const_iterator iface = ifaces_.begin();
         iface != ifaces_.end(); ++iface) {
241
        out << "Detected interface " << iface->getFullName() << endl;
242
243
244
245
        out << "  " << iface->getAddresses().size() << " addr(s):" << endl;
        const AddressCollection addrs = iface->getAddresses();

        for (AddressCollection::const_iterator addr = addrs.begin();
Tomek Mrugalski's avatar
Tomek Mrugalski committed
246
             addr != addrs.end(); ++addr) {
247
            out << "  " << addr->toText() << endl;
248
        }
249
        out << "  mac: " << iface->getPlainMac() << endl;
250
251
252
    }
}

253
254
IfaceMgr::Iface*
IfaceMgr::getIface(int ifindex) {
Tomek Mrugalski's avatar
Tomek Mrugalski committed
255
256
257
    for (IfaceCollection::iterator iface = ifaces_.begin();
         iface != ifaces_.end(); ++iface) {
        if (iface->getIndex() == ifindex) {
258
            return (&(*iface));
Tomek Mrugalski's avatar
Tomek Mrugalski committed
259
        }
260
261
    }

262
    return (NULL); // not found
263
264
}

265
IfaceMgr::Iface*
266
IfaceMgr::getIface(const std::string& ifname) {
Tomek Mrugalski's avatar
Tomek Mrugalski committed
267
268
269
    for (IfaceCollection::iterator iface = ifaces_.begin();
         iface != ifaces_.end(); ++iface) {
        if (iface->getName() == ifname) {
270
            return (&(*iface));
Tomek Mrugalski's avatar
Tomek Mrugalski committed
271
        }
272
273
    }

274
    return (NULL); // not found
275
276
}

277
uint16_t
278
IfaceMgr::openSocket(const std::string& ifname,
279
                     const IOAddress& addr,
280
                     int port) {
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
    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());
    }
}

296
uint16_t
297
IfaceMgr::openSocket4(Iface& iface, const IOAddress& addr, int port) {
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319

    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);
    }

Tomek Mrugalski's avatar
Tomek Mrugalski committed
320
321
    // If there is no support for IP_PKTINFO, we are really out of luck.
    // It will be difficult to understand, where this packet came from.
322
#if defined(IP_PKTINFO)
323
    int flag = 1;
324
    if (setsockopt(sock, IPPROTO_IP, IP_PKTINFO, &flag, sizeof(flag)) != 0) {
325
326
327
328
329
330
331
332
        close(sock);
        isc_throw(Unexpected, "setsockopt: IP_PKTINFO: failed.");
    }
#endif

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

333
    iface.addSocket(SocketInfo(sock, addr, port));
334

335
    return (sock);
336
337
}

338
uint16_t
339
IfaceMgr::openSocket6(Iface& iface, const IOAddress& addr, int port) {
340

341
342
    cout << "Creating UDP6 socket on " << iface.getFullName()
         << " " << addr.toText() << "/port=" << port << endl;
343

344
    struct sockaddr_in6 addr6;
345
346
347
    memset(&addr6, 0, sizeof(addr6));
    addr6.sin6_family = AF_INET6;
    addr6.sin6_port = htons(port);
348
    addr6.sin6_scope_id = if_nametoindex(iface.getName().c_str());
349

350
    memcpy(&addr6.sin6_addr,
351
           addr.getAddress().to_v6().to_bytes().data(),
352
           sizeof(addr6.sin6_addr));
353
#ifdef HAVE_SA_LEN
354
    addr6->sin6_len = sizeof(addr6);
355
356
#endif

357
    // TODO: use sockcreator once it becomes available
358
359
360
361

    // make a socket
    int sock = socket(AF_INET6, SOCK_DGRAM, 0);
    if (sock < 0) {
362
        isc_throw(Unexpected, "Failed to create UDP6 socket.");
363
364
    }

Tomek Mrugalski's avatar
Tomek Mrugalski committed
365
366
    // Set the REUSEADDR option so that we don't fail to start if
    // we're being restarted.
367
368
369
    int flag = 1;
    if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR,
                   (char *)&flag, sizeof(flag)) < 0) {
370
        close(sock);
371
        isc_throw(Unexpected, "Can't set SO_REUSEADDR option on dhcpv6 socket.");
372
373
    }

374
    if (bind(sock, (struct sockaddr *)&addr6, sizeof(addr6)) < 0) {
375
        close(sock);
376
377
        isc_throw(Unexpected, "Failed to bind socket " << sock << " to " << addr.toText()
                  << "/port=" << port);
378
379
    }
#ifdef IPV6_RECVPKTINFO
Tomek Mrugalski's avatar
Tomek Mrugalski committed
380
    // RFC3542 - a new way
381
382
    if (setsockopt(sock, IPPROTO_IPV6, IPV6_RECVPKTINFO,
                   &flag, sizeof(flag)) != 0) {
383
        close(sock);
384
        isc_throw(Unexpected, "setsockopt: IPV6_RECVPKTINFO failed.");
385
386
    }
#else
Tomek Mrugalski's avatar
Tomek Mrugalski committed
387
    // RFC2292 - an old way
388
389
    if (setsockopt(sock, IPPROTO_IPV6, IPV6_PKTINFO,
                   &flag, sizeof(flag)) != 0) {
390
        close(sock);
391
        isc_throw(Unexpected, "setsockopt: IPV6_PKTINFO: failed.");
392
393
394
395
    }
#endif

    // multicast stuff
396
    if (addr.getAddress().to_v6().is_multicast()) {
397
        // both mcast (ALL_DHCP_RELAY_AGENTS_AND_SERVERS and ALL_DHCP_SERVERS)
398
399
        // are link and site-scoped, so there is no sense to join those groups
        // with global addresses.
400

401
        if ( !joinMcast( sock, iface.getName(),
402
403
                         string(ALL_DHCP_RELAY_AGENTS_AND_SERVERS) ) ) {
            close(sock);
404
405
            isc_throw(Unexpected, "Failed to join " << ALL_DHCP_RELAY_AGENTS_AND_SERVERS
                      << " multicast group.");
406
407
408
        }
    }

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

412
    iface.addSocket(SocketInfo(sock, addr, port));
413

414
    return (sock);
415
416
}

417
418
419
bool
IfaceMgr::joinMcast(int sock, const std::string& ifname,
const std::string & mcast) {
420
421
422

    struct ipv6_mreq mreq;

423
424
425
426
427
    if (inet_pton(AF_INET6, mcast.c_str(),
                  &mreq.ipv6mr_multiaddr) <= 0) {
        cout << "Failed to convert " << ifname
             << " to IPv6 multicast address." << endl;
        return (false);
428
429
    }

430
431
432
433
434
    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);
435
436
    }

437
    cout << "Joined multicast " << mcast << " group." << endl;
438

439
440
    return (true);
}
441

442
bool
443
IfaceMgr::send(boost::shared_ptr<Pkt6>& pkt) {
444
445
446
447
448
    struct msghdr m;
    struct iovec v;
    int result;
    struct in6_pktinfo *pktinfo;
    struct cmsghdr *cmsg;
449
450
451
452
453
454
455

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

456
    memset(&control_buf_[0], 0, control_buf_len_);
457

Tomek Mrugalski's avatar
Tomek Mrugalski committed
458
    // Initialize our message header structure.
459
460
    memset(&m, 0, sizeof(m));

Tomek Mrugalski's avatar
Tomek Mrugalski committed
461
    // Set the target address we're sending to.
462
463
464
    sockaddr_in6 to;
    memset(&to, 0, sizeof(to));
    to.sin6_family = AF_INET6;
465
    to.sin6_port = htons(pkt->remote_port_);
466
    memcpy(&to.sin6_addr,
467
           pkt->remote_addr_.getAddress().to_v6().to_bytes().data(),
468
           16);
469
    to.sin6_scope_id = pkt->ifindex_;
470
471
472
473

    m.msg_name = &to;
    m.msg_namelen = sizeof(to);

Tomek Mrugalski's avatar
Tomek Mrugalski committed
474
475
476
    // 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.)
477
478
    v.iov_base = (char *) &pkt->data_[0];
    v.iov_len = pkt->data_len_;
479
480
481
    m.msg_iov = &v;
    m.msg_iovlen = 1;

Tomek Mrugalski's avatar
Tomek Mrugalski committed
482
483
484
485
486
487
    // 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.
488
    m.msg_control = &control_buf_[0];
489
490
491
492
493
494
495
    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));
496
    pktinfo->ipi6_ifindex = pkt->ifindex_;
497
498
    m.msg_controllen = cmsg->cmsg_len;

499
    result = sendmsg(getSocket(*pkt), &m, 0);
500
501
502
    if (result < 0) {
        cout << "Send packet failed." << endl;
    }
503
504
    cout << "Sent " << pkt->data_len_ << " bytes over socket " << getSocket(*pkt)
         << " on " << iface->getFullName() << " interface: "
505
506
         << " dst=" << pkt->remote_addr_.toText()
         << ", src=" << pkt->local_addr_.toText()
507
         << endl;
508

509
510
    return (result);
}
511

512
513
514
515
bool
IfaceMgr::send(boost::shared_ptr<Pkt4>& )
{
    /// TODO: Implement this (ticket #1240)
516
    isc_throw(NotImplemented, "Pkt4 send not implemented yet.");
517
518
519
}


520
521
boost::shared_ptr<Pkt4>
IfaceMgr::receive4() {
522
    isc_throw(NotImplemented, "Pkt4 reception not implemented yet.");
523
524

    // TODO: To be implemented (ticket #1239)
525
526
527
    return (boost::shared_ptr<Pkt4>()); // NULL
}

528
boost::shared_ptr<Pkt6>
529
IfaceMgr::receive6() {
530
531
532
533
534
535
536
    struct msghdr m;
    struct iovec v;
    int result;
    struct cmsghdr* cmsg;
    struct in6_pktinfo* pktinfo;
    struct sockaddr_in6 from;
    struct in6_addr to_addr;
537
    boost::shared_ptr<Pkt6> pkt;
538
    char addr_str[INET6_ADDRSTRLEN];
539
540

    try {
541
542
543
544
545
546
547
        // 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
548
        pkt = boost::shared_ptr<Pkt6>(new Pkt6(65536));
549
    } catch (const std::exception& ex) {
550
        cout << "Failed to create new packet." << endl;
551
        return (boost::shared_ptr<Pkt6>()); // NULL
552
    }
553

554
    memset(&control_buf_[0], 0, control_buf_len_);
555
556
557
558

    memset(&from, 0, sizeof(from));
    memset(&to_addr, 0, sizeof(to_addr));

Tomek Mrugalski's avatar
Tomek Mrugalski committed
559
    // Initialize our message header structure.
560
561
    memset(&m, 0, sizeof(m));

Tomek Mrugalski's avatar
Tomek Mrugalski committed
562
    // Point so we can get the from address.
563
564
565
    m.msg_name = &from;
    m.msg_namelen = sizeof(from);

Tomek Mrugalski's avatar
Tomek Mrugalski committed
566
567
568
    // 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.)
569
    v.iov_base = (void*)&pkt->data_[0];
570
571
572
573
    v.iov_len = pkt->data_len_;
    m.msg_iov = &v;
    m.msg_iovlen = 1;

Tomek Mrugalski's avatar
Tomek Mrugalski committed
574
575
576
577
578
579
    // 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.
580
    m.msg_control = &control_buf_[0];
581
582
    m.msg_controllen = control_buf_len_;

583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
    /// 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);
611
612

    if (result >= 0) {
Tomek Mrugalski's avatar
Tomek Mrugalski committed
613
614
615
616
617
618
        // 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.
619
620
621
622
623
624
625
626
627
        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;
628
            }
629
630
631
632
            cmsg = CMSG_NXTHDR(&m, cmsg);
        }
        if (!found_pktinfo) {
            cout << "Unable to find pktinfo" << endl;
633
            return (boost::shared_ptr<Pkt6>()); // NULL
634
        }
635
636
    } else {
        cout << "Failed to receive data." << endl;
637
        return (boost::shared_ptr<Pkt6>()); // NULL
638
    }
639

640
    // That's ugly.
641
    // TODO add IOAddress constructor that will take struct in6_addr*
642
    // TODO: there's from_bytes() method added in IOAddress. Use it!
643
644
645
    inet_ntop(AF_INET6, &to_addr, addr_str,INET6_ADDRSTRLEN);
    pkt->local_addr_ = IOAddress(string(addr_str));

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

650
651
652
653
    pkt->remote_port_ = ntohs(from.sin6_port);

    Iface* received = getIface(pkt->ifindex_);
    if (received) {
654
        pkt->iface_ = received->getName();
655
656
    } else {
        cout << "Received packet over unknown interface (ifindex="
657
             << pkt->ifindex_ << ")." << endl;
658
        return (boost::shared_ptr<Pkt6>()); // NULL
659
    }
660

661
    pkt->data_len_ = result;
662

663
664
665
    // TODO Move this to LOG_DEBUG
    cout << "Received " << pkt->data_len_ << " bytes over "
         << pkt->iface_ << "/" << pkt->ifindex_ << " interface: "
666
667
         << " src=" << pkt->remote_addr_.toText()
         << ", dst=" << pkt->local_addr_.toText()
668
         << endl;
669

670
671
    return (pkt);
}
672

673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
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
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.");
}



729
}