/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 | | |