dhcp6to4_ipc.cc 4.78 KB
Newer Older
1
// Copyright (C) 2015-2017 Internet Systems Consortium, Inc. ("ISC")
2
//
3 4 5
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
6 7 8 9 10

#include <config.h>

#include <util/buffer.h>
#include <dhcp/iface_mgr.h>
11 12
#include <dhcp/pkt6.h>
#include <dhcpsrv/callout_handle_store.h>
13
#include <dhcpsrv/cfgmgr.h>
14
#include <dhcp6/dhcp6to4_ipc.h>
15 16 17 18 19 20 21
#include <dhcp6/dhcp6_log.h>
#include <dhcp6/dhcp6_srv.h>
#include <exceptions/exceptions.h>
#include <hooks/callout_handle.h>
#include <hooks/hooks_log.h>
#include <hooks/hooks_manager.h>
#include <stats/stats_mgr.h>
22 23

using namespace std;
24
using namespace isc::hooks;
25 26 27 28

namespace isc {
namespace dhcp {

29
Dhcp6to4Ipc::Dhcp6to4Ipc() : Dhcp4o6IpcBase() {}
30

31 32 33
Dhcp6to4Ipc& Dhcp6to4Ipc::instance() {
    static Dhcp6to4Ipc dhcp6to4_ipc;
    return (dhcp6to4_ipc);
34 35
}

36
void Dhcp6to4Ipc::open() {
37
    uint16_t port = CfgMgr::instance().getStagingCfg()->getDhcp4o6Port();
38 39 40 41 42 43 44 45 46
    if (port == 0) {
        Dhcp4o6IpcBase::close();
        return;
    }
    if (port > 65534) {
        isc_throw(OutOfRange, "DHCP4o6 port " << port);
    }

    int old_fd = socket_fd_;
47
    socket_fd_ = Dhcp4o6IpcBase::open(port, ENDPOINT_TYPE_V6);
48
    if ((old_fd == -1) && (socket_fd_ != old_fd)) {
49 50
        IfaceMgr::instance().addExternalSocket(socket_fd_,
                                               Dhcp6to4Ipc::handler);
51 52 53
    }
}

54 55
void Dhcp6to4Ipc::handler() {
    Dhcp6to4Ipc& ipc = Dhcp6to4Ipc::instance();
56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72
    Pkt6Ptr pkt;

    try {
        LOG_DEBUG(packet6_logger, DBG_DHCP6_DETAIL, DHCP6_DHCP4O6_RECEIVING);
        // Receive message from IPC.
        pkt = ipc.receive();

        if (pkt) {
            LOG_DEBUG(packet6_logger, DBG_DHCP6_BASIC, DHCP6_DHCP4O6_PACKET_RECEIVED)
                .arg(static_cast<int>(pkt->getType()))
                .arg(pkt->getRemoteAddr().toText())
                .arg(pkt->getIface());
        }
    } catch (const std::exception& e) {
        LOG_DEBUG(packet6_logger,DBG_DHCP6_DETAIL, DHCP6_DHCP4O6_RECEIVE_FAIL)
            .arg(e.what());
    }
73

74 75 76
    if (!pkt) {
        return;
    }
77

78 79
    // Should we check it is a DHCPV6_DHCPV4_RESPONSE?

80 81 82
    // The received message has been unpacked by the receive() function. This
    // method could have modified the message so it's better to pack() it
    // again because we'll be forwarding it to a client.
83
    isc::util::OutputBuffer& buf = pkt->getBuffer();
84 85 86
    buf.clear();
    pkt->pack();

Francis Dupont's avatar
Francis Dupont committed
87 88
    // Don't use getType(): get the message type from the buffer as we
    // want to know if it is a relayed message (vs. internal message type).
89
    // getType() always returns the type of internal message.
90
    uint8_t msg_type = buf[0];
91 92 93 94 95
    if ((msg_type == DHCPV6_RELAY_FORW) || (msg_type == DHCPV6_RELAY_REPL)) {
        pkt->setRemotePort(DHCP6_SERVER_PORT);
    } else {
        pkt->setRemotePort(DHCP6_CLIENT_PORT);
    }
96

97 98 99 100 101 102
    // Can't call the pkt6_send callout because we don't have the query

    // Copied from Dhcpv6Srv::run_one() sending part

    try {
        // Let's execute all callouts registered for buffer6_send
Francis Dupont's avatar
Francis Dupont committed
103
        if (HooksManager::calloutsPresent(Dhcpv6Srv::getHookIndexBuffer6Send())) {
104 105 106 107 108
            CalloutHandlePtr callout_handle = getCalloutHandle(pkt);

            // Delete previously set arguments
            callout_handle->deleteAllArguments();

109 110 111
            // Enable copying options from the packet within hook library.
            ScopedEnableOptionsCopy<Pkt6> response6_options_copy(pkt);

112 113 114 115
            // Pass incoming packet as argument
            callout_handle->setArgument("response6", pkt);

            // Call callouts
Francis Dupont's avatar
Francis Dupont committed
116
            HooksManager::callCallouts(Dhcpv6Srv::getHookIndexBuffer6Send(),
117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145
                                       *callout_handle);

            // Callouts decided to skip the next processing step. The next
            // processing step would to parse the packet, so skip at this
            // stage means drop.
            if (callout_handle->getStatus() == CalloutHandle::NEXT_STEP_SKIP) {
                LOG_DEBUG(hooks_logger, DBG_DHCP6_HOOKS, DHCP6_HOOK_BUFFER_SEND_SKIP)
                    .arg(pkt->getLabel());
                return;
            }

            /// @todo: Add support for DROP status

            callout_handle->getArgument("response6", pkt);
        }

        LOG_DEBUG(packet6_logger, DBG_DHCP6_DETAIL_DATA, DHCP6_RESPONSE_DATA)
            .arg(static_cast<int>(pkt->getType())).arg(pkt->toText());


        // Forward packet to the client.
        IfaceMgr::instance().send(pkt);

        // Update statistics accordingly for sent packet.
        Dhcpv6Srv::processStatsSent(pkt);

    } catch (const std::exception& e) {
        LOG_ERROR(packet6_logger, DHCP6_DHCP4O6_SEND_FAIL).arg(e.what());
    }
146 147 148 149 150
}

};  // namespace dhcp

};  // namespace isc