Coverage Report

Created: 2025-11-16 07:29

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/kea/src/bin/dhcp6/dhcp6to4_ipc.cc
Line
Count
Source
1
// Copyright (C) 2015-2024 Internet Systems Consortium, Inc. ("ISC")
2
//
3
// This Source Code Form is subject to the terms of the Mozilla Public
4
// License, v. 2.0. If a copy of the MPL was not distributed with this
5
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
6
7
#include <config.h>
8
9
#include <util/buffer.h>
10
#include <dhcp/iface_mgr.h>
11
#include <dhcp/pkt6.h>
12
#include <dhcpsrv/callout_handle_store.h>
13
#include <dhcpsrv/cfgmgr.h>
14
#include <dhcp6/dhcp6to4_ipc.h>
15
#include <dhcp6/dhcp6_log.h>
16
#include <dhcp6/ctrl_dhcp6_srv.h>
17
#include <dhcp6/dhcp6_srv.h>
18
#include <exceptions/exceptions.h>
19
#include <hooks/callout_handle.h>
20
#include <hooks/hooks_log.h>
21
#include <hooks/hooks_manager.h>
22
#include <stats/stats_mgr.h>
23
24
using namespace std;
25
using namespace isc::hooks;
26
27
namespace isc {
28
namespace dhcp {
29
30
uint16_t Dhcp6to4Ipc::client_port = 0;
31
32
10
Dhcp6to4Ipc::Dhcp6to4Ipc() : Dhcp4o6IpcBase() {}
33
34
41.0k
Dhcp6to4Ipc& Dhcp6to4Ipc::instance() {
35
41.0k
    static Dhcp6to4Ipc dhcp6to4_ipc;
36
41.0k
    return (dhcp6to4_ipc);
37
41.0k
}
38
39
8.70k
void Dhcp6to4Ipc::open() {
40
8.70k
    uint16_t port = CfgMgr::instance().getStagingCfg()->getDhcp4o6Port();
41
8.70k
    if (port == 0) {
42
8.70k
        Dhcp4o6IpcBase::close();
43
8.70k
        return;
44
8.70k
    }
45
0
    if (port > 65534) {
46
0
        isc_throw(OutOfRange, "DHCP4o6 port " << port);
47
0
    }
48
49
0
    int old_fd = socket_fd_;
50
0
    socket_fd_ = Dhcp4o6IpcBase::open(port, ENDPOINT_TYPE_V6);
51
0
    if ((old_fd == -1) && (socket_fd_ != old_fd)) {
52
0
        IfaceMgr::instance().addExternalSocket(socket_fd_,
53
0
                                               Dhcp6to4Ipc::handler);
54
0
    }
55
0
}
56
57
0
void Dhcp6to4Ipc::handler(int /* fd */) {
58
0
    Dhcp6to4Ipc& ipc = Dhcp6to4Ipc::instance();
59
0
    Pkt6Ptr pkt;
60
61
0
    try {
62
0
        LOG_DEBUG(packet6_logger, DBG_DHCP6_DETAIL, DHCP6_DHCP4O6_RECEIVING);
63
        // Receive message from IPC.
64
0
        pkt = ipc.receive();
65
66
0
        if (pkt) {
67
0
            LOG_DEBUG(packet6_logger, DBG_DHCP6_BASIC, DHCP6_DHCP4O6_PACKET_RECEIVED)
68
0
                .arg(static_cast<int>(pkt->getType()))
69
0
                .arg(pkt->getRemoteAddr().toText())
70
0
                .arg(pkt->getRemotePort())
71
0
                .arg(pkt->getIface());
72
0
        }
73
0
    } catch (const std::exception& e) {
74
0
        LOG_DEBUG(packet6_logger,DBG_DHCP6_DETAIL, DHCP6_DHCP4O6_RECEIVE_FAIL)
75
0
            .arg(e.what());
76
0
    }
77
78
0
    if (!pkt) {
79
0
        return;
80
0
    }
81
82
    // Should we check it is a DHCPV6_DHCPV4_RESPONSE?
83
84
    // Handle relay port
85
0
    uint16_t relay_port = Dhcpv6Srv::checkRelaySourcePort(pkt);
86
87
    // The received message has been unpacked by the receive() function. This
88
    // method could have modified the message so it's better to pack() it
89
    // again because we'll be forwarding it to a client.
90
0
    isc::util::OutputBuffer& buf = pkt->getBuffer();
91
0
    buf.clear();
92
0
    pkt->pack();
93
94
    // Don't use getType(): get the message type from the buffer as we
95
    // want to know if it is a relayed message (vs. internal message type).
96
    // getType() always returns the type of internal message.
97
0
    uint8_t msg_type = buf[0];
98
0
    if (client_port) {
99
0
        pkt->setRemotePort(client_port);
100
0
    } else if ((msg_type == DHCPV6_RELAY_FORW) ||
101
0
               (msg_type == DHCPV6_RELAY_REPL)) {
102
0
        pkt->setRemotePort(relay_port ? relay_port : DHCP6_SERVER_PORT);
103
0
    } else {
104
0
        pkt->setRemotePort(DHCP6_CLIENT_PORT);
105
0
    }
106
107
    // Can't call the pkt6_send callout because we don't have the query
108
    // From Dhcpv6Srv::processPacketBufferSend
109
110
0
    try {
111
        // Let's execute all callouts registered for buffer6_send
112
0
        if (HooksManager::calloutsPresent(Dhcpv6Srv::getHookIndexBuffer6Send())) {
113
0
            CalloutHandlePtr callout_handle = getCalloutHandle(pkt);
114
115
            // Delete previously set arguments
116
0
            callout_handle->deleteAllArguments();
117
118
            // Use the RAII wrapper to make sure that the callout handle state is
119
            // reset when this object goes out of scope. All hook points must do
120
            // it to prevent possible circular dependency between the callout
121
            // handle and its arguments.
122
0
            ScopedCalloutHandleState callout_handle_state(callout_handle);
123
124
            // Enable copying options from the packet within hook library.
125
0
            ScopedEnableOptionsCopy<Pkt6> response6_options_copy(pkt);
126
127
            // Pass incoming packet as argument
128
0
            callout_handle->setArgument("response6", pkt);
129
130
            // Call callouts
131
0
            HooksManager::callCallouts(Dhcpv6Srv::getHookIndexBuffer6Send(),
132
0
                                       *callout_handle);
133
134
            // Callouts decided to skip the next processing step. The next
135
            // processing step would be to parse the packet, so skip at this
136
            // stage means drop.
137
0
            if ((callout_handle->getStatus() == CalloutHandle::NEXT_STEP_SKIP) ||
138
0
                (callout_handle->getStatus() == CalloutHandle::NEXT_STEP_DROP)) {
139
0
                LOG_DEBUG(hooks_logger, DBG_DHCP6_HOOKS,
140
0
                          DHCP6_HOOK_BUFFER_SEND_SKIP)
141
0
                    .arg(pkt->getLabel());
142
0
                return;
143
0
            }
144
145
0
            callout_handle->getArgument("response6", pkt);
146
0
        }
147
148
0
        LOG_DEBUG(packet6_logger, DBG_DHCP6_DETAIL_DATA, DHCP6_DHCP4O6_RESPONSE_DATA)
149
0
            .arg(pkt->getLabel())
150
0
            .arg(pkt->getName())
151
0
            .arg(static_cast<int>(pkt->getType()))
152
0
            .arg(pkt->toText());
153
154
        // Forward packet to the client.
155
0
        IfaceMgr::instance().send(pkt);
156
157
        // Update statistics accordingly for sent packet.
158
0
        Dhcpv6Srv::processStatsSent(pkt);
159
160
0
    } catch (const std::exception& e) {
161
0
        LOG_ERROR(packet6_logger, DHCP6_DHCP4O6_SEND_FAIL)
162
0
            .arg(pkt->getLabel())
163
0
            .arg(e.what());
164
0
    }
165
0
}
166
167
} // namespace dhcp
168
169
} // namespace isc
170