dhcp4to6_ipc.cc 5.93 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 13 14
#include <dhcp/pkt4.h>
#include <dhcp/pkt4o6.h>
#include <dhcp/pkt6.h>
#include <dhcpsrv/callout_handle_store.h>
15
#include <dhcpsrv/cfgmgr.h>
16
#include <dhcp4/ctrl_dhcp4_srv.h>
17
#include <dhcp4/dhcp4to6_ipc.h>
18 19 20 21
#include <dhcp4/dhcp4_log.h>
#include <hooks/callout_handle.h>
#include <hooks/hooks_log.h>
#include <hooks/hooks_manager.h>
22 23

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

namespace isc {
namespace dhcp {

30
Dhcp4to6Ipc::Dhcp4to6Ipc() : Dhcp4o6IpcBase() {}
31

32 33 34
Dhcp4to6Ipc& Dhcp4to6Ipc::instance() {
    static Dhcp4to6Ipc dhcp4to6_ipc;
    return (dhcp4to6_ipc);
35 36
}

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

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

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

    try {
        LOG_DEBUG(packet4_logger, DBG_DHCP4_DETAIL, DHCP4_DHCP4O6_RECEIVING);
        // Receive message from the IPC socket.
        pkt = ipc.receive();

        // from Dhcpv4Srv::run_one() after receivePacket()
        if (pkt) {
            LOG_DEBUG(packet4_logger, DBG_DHCP4_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(packet4_logger, DBG_DHCP4_DETAIL, DHCP4_DHCP4O6_RECEIVE_FAIL)
            .arg(e.what());
    }
75

76 77 78 79
    if (!pkt) {
        return;
    }

80
    // Each message must contain option holding DHCPv4 message.
81
    OptionCollection msgs = pkt->getOptions(D6O_DHCPV4_MSG);
82
    if (msgs.empty()) {
83 84 85
        LOG_DEBUG(packet4_logger, DBG_DHCP4_DETAIL, DHCP4_DHCP4O6_BAD_PACKET)
            .arg("DHCPv4 message option not present");
        return;
86
    } else if (msgs.size() > 1) {
87 88 89
        LOG_DEBUG(packet4_logger, DBG_DHCP4_DETAIL, DHCP4_DHCP4O6_BAD_PACKET)
            .arg("more than one DHCPv4 message option");
        return;
90
    }
91

92
    // Get the DHCPv4 message 
93
    OptionPtr msg = msgs.begin()->second;
94
    if (!msg) {
95 96 97
        LOG_DEBUG(packet4_logger, DBG_DHCP4_DETAIL, DHCP4_DHCP4O6_BAD_PACKET)
            .arg("null DHCPv4 message option");
        return;
98
    }
99

100 101
    // Extract the DHCPv4 packet with DHCPv6 packet attached
    Pkt4Ptr query(new Pkt4o6(msg->getData(), pkt));
102

103 104 105
    // From Dhcpv4Srv::run_one() processing and after
    Pkt4Ptr rsp;

106
    ControlledDhcpv4Srv::getInstance()->processPacket(query, rsp, false);
107 108 109 110 111 112 113 114 115 116

    if (!rsp) {
        return;
    }

    try {
        // Now all fields and options are constructed into output wire buffer.
        // Option objects modification does not make sense anymore. Hooks
        // can only manipulate wire buffer at this stage.
        // Let's execute all callouts registered for buffer4_send
Francis Dupont's avatar
Francis Dupont committed
117
      if (HooksManager::calloutsPresent(Dhcpv4Srv::getHookIndexBuffer4Send())) {
118 119 120 121 122
            CalloutHandlePtr callout_handle = getCalloutHandle(query);

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

123 124 125
            // Enable copying options from the packet within hook library.
            ScopedEnableOptionsCopy<Pkt4> response4_options_copy(rsp);

126 127 128 129
            // Pass incoming packet as argument
            callout_handle->setArgument("response4", rsp);

            // Call callouts
Francis Dupont's avatar
Francis Dupont committed
130
            HooksManager::callCallouts(Dhcpv4Srv::getHookIndexBuffer4Send(),
131 132 133 134 135
                                       *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.
136 137
            if ((callout_handle->getStatus() == CalloutHandle::NEXT_STEP_SKIP) ||
                (callout_handle->getStatus() == CalloutHandle::NEXT_STEP_DROP)) {
138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179
                LOG_DEBUG(hooks_logger, DBG_DHCP4_HOOKS,
                          DHCP4_HOOK_BUFFER_SEND_SKIP)
                    .arg(rsp->getLabel());
                return;
            }

            callout_handle->getArgument("response4", rsp);
        }

        Pkt4o6Ptr rsp6 = boost::dynamic_pointer_cast<Pkt4o6>(rsp);
        // Should not happen
        if (!rsp6) {
            isc_throw(Unexpected, "Dhcp4o6 packet cast fail");
        }

        LOG_DEBUG(packet4_logger, DBG_DHCP4_BASIC, DHCP4_DHCP4O6_PACKET_SEND)
            .arg(rsp6->getLabel())
            .arg(rsp6->getName())
            .arg(static_cast<int>(rsp6->getType()))
            .arg(rsp6->getRemoteAddr())
            .arg(rsp6->getIface())
            .arg(rsp->getLabel())
            .arg(rsp->getName())
            .arg(static_cast<int>(rsp->getType()));

        LOG_DEBUG(packet4_logger, DBG_DHCP4_DETAIL_DATA,
                  DHCP4_DHCP4O6_RESPONSE_DATA)
            .arg(rsp6->getLabel())
            .arg(rsp6->getName())
            .arg(static_cast<int>(rsp6->getType()))
            .arg(rsp6->toText());

        ipc.send(rsp6->getPkt6());

        // Update statistics accordingly for sent packet.
        Dhcpv4Srv::processStatsSent(rsp);

    } catch (const std::exception& e) {
        LOG_ERROR(packet4_logger, DHCP4_DHCP4O6_PACKET_SEND_FAIL)
            .arg(rsp->getLabel())
            .arg(e.what());
    }
180 181 182 183 184
}

};  // namespace dhcp

};  // namespace isc