Serenity Operating System
1/*
2 * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 *
8 * 1. Redistributions of source code must retain the above copyright notice, this
9 * list of conditions and the following disclaimer.
10 *
11 * 2. Redistributions in binary form must reproduce the above copyright notice,
12 * this list of conditions and the following disclaimer in the documentation
13 * and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
16 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
18 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
21 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
22 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
23 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
24 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 */
26
27#include <AK/StringBuilder.h>
28#include <Kernel/FileSystem/FileDescription.h>
29#include <Kernel/Net/ARP.h>
30#include <Kernel/Net/ICMP.h>
31#include <Kernel/Net/IPv4.h>
32#include <Kernel/Net/IPv4Socket.h>
33#include <Kernel/Net/NetworkAdapter.h>
34#include <Kernel/Net/Routing.h>
35#include <Kernel/Net/TCP.h>
36#include <Kernel/Net/TCPSocket.h>
37#include <Kernel/Net/UDP.h>
38#include <Kernel/Net/UDPSocket.h>
39#include <Kernel/Process.h>
40#include <Kernel/UnixTypes.h>
41#include <LibC/errno_numbers.h>
42#include <LibC/sys/ioctl_numbers.h>
43
44//#define IPV4_SOCKET_DEBUG
45
46namespace Kernel {
47
48Lockable<HashTable<IPv4Socket*>>& IPv4Socket::all_sockets()
49{
50 static Lockable<HashTable<IPv4Socket*>>* s_table;
51 if (!s_table)
52 s_table = new Lockable<HashTable<IPv4Socket*>>;
53 return *s_table;
54}
55
56KResultOr<NonnullRefPtr<Socket>> IPv4Socket::create(int type, int protocol)
57{
58 if (type == SOCK_STREAM)
59 return TCPSocket::create(protocol);
60 if (type == SOCK_DGRAM)
61 return UDPSocket::create(protocol);
62 if (type == SOCK_RAW)
63 return adopt(*new IPv4Socket(type, protocol));
64 return KResult(-EINVAL);
65}
66
67IPv4Socket::IPv4Socket(int type, int protocol)
68 : Socket(AF_INET, type, protocol)
69{
70#ifdef IPV4_SOCKET_DEBUG
71 dbg() << "IPv4Socket{" << this << "} created with type=" << type << ", protocol=" << protocol;
72#endif
73 m_buffer_mode = type == SOCK_STREAM ? BufferMode::Bytes : BufferMode::Packets;
74 if (m_buffer_mode == BufferMode::Bytes) {
75 m_scratch_buffer = KBuffer::create_with_size(65536);
76 }
77 LOCKER(all_sockets().lock());
78 all_sockets().resource().set(this);
79}
80
81IPv4Socket::~IPv4Socket()
82{
83 LOCKER(all_sockets().lock());
84 all_sockets().resource().remove(this);
85}
86
87void IPv4Socket::get_local_address(sockaddr* address, socklen_t* address_size)
88{
89 sockaddr_in local_address = { AF_INET, htons(m_local_port), { m_local_address.to_in_addr_t() }, { 0 } };
90 memcpy(address, &local_address, min(static_cast<size_t>(*address_size), sizeof(sockaddr_in)));
91 *address_size = sizeof(sockaddr_in);
92}
93
94void IPv4Socket::get_peer_address(sockaddr* address, socklen_t* address_size)
95{
96 sockaddr_in peer_address = { AF_INET, htons(m_peer_port), { m_peer_address.to_in_addr_t() }, { 0 } };
97 memcpy(address, &peer_address, min(static_cast<size_t>(*address_size), sizeof(sockaddr_in)));
98 *address_size = sizeof(sockaddr_in);
99}
100
101KResult IPv4Socket::bind(const sockaddr* user_address, socklen_t address_size)
102{
103 ASSERT(setup_state() == SetupState::Unstarted);
104 if (address_size != sizeof(sockaddr_in))
105 return KResult(-EINVAL);
106
107 sockaddr_in address;
108 copy_from_user(&address, user_address, sizeof(sockaddr_in));
109
110 if (address.sin_family != AF_INET)
111 return KResult(-EINVAL);
112
113 auto requested_local_port = ntohs(address.sin_port);
114 if (!Process::current->is_superuser()) {
115 if (requested_local_port < 1024) {
116 dbg() << "UID " << Process::current->uid() << " attempted to bind " << class_name() << " to port " << requested_local_port;
117 return KResult(-EACCES);
118 }
119 }
120
121 m_local_address = IPv4Address((const u8*)&address.sin_addr.s_addr);
122 m_local_port = requested_local_port;
123
124#ifdef IPV4_SOCKET_DEBUG
125 dbg() << "IPv4Socket::bind " << class_name() << "{" << this << "} to " << m_local_address << ":" << m_local_port;
126#endif
127
128 return protocol_bind();
129}
130
131KResult IPv4Socket::listen(size_t backlog)
132{
133 int rc = allocate_local_port_if_needed();
134 if (rc < 0)
135 return KResult(-EADDRINUSE);
136
137 set_backlog(backlog);
138 m_role = Role::Listener;
139
140#ifdef IPV4_SOCKET_DEBUG
141 dbg() << "IPv4Socket{" << this << "} listening with backlog=" << backlog;
142#endif
143
144 return protocol_listen();
145}
146
147KResult IPv4Socket::connect(FileDescription& description, const sockaddr* address, socklen_t address_size, ShouldBlock should_block)
148{
149 if (address_size != sizeof(sockaddr_in))
150 return KResult(-EINVAL);
151 if (address->sa_family != AF_INET)
152 return KResult(-EINVAL);
153 if (m_role == Role::Connected)
154 return KResult(-EISCONN);
155
156 auto& ia = *(const sockaddr_in*)address;
157 m_peer_address = IPv4Address((const u8*)&ia.sin_addr.s_addr);
158 m_peer_port = ntohs(ia.sin_port);
159
160 return protocol_connect(description, should_block);
161}
162
163void IPv4Socket::attach(FileDescription&)
164{
165}
166
167void IPv4Socket::detach(FileDescription&)
168{
169}
170
171bool IPv4Socket::can_read(const FileDescription&) const
172{
173 if (m_role == Role::Listener)
174 return can_accept();
175 if (protocol_is_disconnected())
176 return true;
177 return m_can_read;
178}
179
180bool IPv4Socket::can_write(const FileDescription&) const
181{
182 return is_connected();
183}
184
185int IPv4Socket::allocate_local_port_if_needed()
186{
187 if (m_local_port)
188 return m_local_port;
189 int port = protocol_allocate_local_port();
190 if (port < 0)
191 return port;
192 m_local_port = (u16)port;
193 return port;
194}
195
196ssize_t IPv4Socket::sendto(FileDescription&, const void* data, size_t data_length, int flags, const sockaddr* addr, socklen_t addr_length)
197{
198 (void)flags;
199 if (addr && addr_length != sizeof(sockaddr_in))
200 return -EINVAL;
201
202 if (addr) {
203 if (addr->sa_family != AF_INET) {
204 klog() << "sendto: Bad address family: " << addr->sa_family << " is not AF_INET!";
205 return -EAFNOSUPPORT;
206 }
207
208 auto& ia = *(const sockaddr_in*)addr;
209 m_peer_address = IPv4Address((const u8*)&ia.sin_addr.s_addr);
210 m_peer_port = ntohs(ia.sin_port);
211 }
212
213 auto routing_decision = route_to(m_peer_address, m_local_address, bound_interface());
214 if (routing_decision.is_zero())
215 return -EHOSTUNREACH;
216
217 if (m_local_address.to_u32() == 0)
218 m_local_address = routing_decision.adapter->ipv4_address();
219
220 int rc = allocate_local_port_if_needed();
221 if (rc < 0)
222 return rc;
223
224#ifdef IPV4_SOCKET_DEBUG
225 klog() << "sendto: destination=" << m_peer_address.to_string().characters() << ":" << m_peer_port;
226#endif
227
228 if (type() == SOCK_RAW) {
229 routing_decision.adapter->send_ipv4(routing_decision.next_hop, m_peer_address, (IPv4Protocol)protocol(), (const u8*)data, data_length, m_ttl);
230 return data_length;
231 }
232
233 int nsent = protocol_send(data, data_length);
234 if (nsent > 0)
235 Thread::current->did_ipv4_socket_write(nsent);
236 return nsent;
237}
238
239ssize_t IPv4Socket::receive_byte_buffered(FileDescription& description, void* buffer, size_t buffer_length, int, sockaddr*, socklen_t*)
240{
241 Locker locker(lock());
242 if (m_receive_buffer.is_empty()) {
243 if (protocol_is_disconnected())
244 return 0;
245 if (!description.is_blocking())
246 return -EAGAIN;
247
248 locker.unlock();
249 auto res = Thread::current->block<Thread::ReadBlocker>(description);
250 locker.lock();
251
252 if (!m_can_read) {
253 if (res != Thread::BlockResult::WokeNormally)
254 return -EINTR;
255
256 // Unblocked due to timeout.
257 return -EAGAIN;
258 }
259 }
260
261 ASSERT(!m_receive_buffer.is_empty());
262 int nreceived = m_receive_buffer.read((u8*)buffer, buffer_length);
263 if (nreceived > 0)
264 Thread::current->did_ipv4_socket_read((size_t)nreceived);
265
266 m_can_read = !m_receive_buffer.is_empty();
267 return nreceived;
268}
269
270ssize_t IPv4Socket::receive_packet_buffered(FileDescription& description, void* buffer, size_t buffer_length, int flags, sockaddr* addr, socklen_t* addr_length)
271{
272 Locker locker(lock());
273 ReceivedPacket packet;
274 {
275 if (m_receive_queue.is_empty()) {
276 // FIXME: Shouldn't this return -ENOTCONN instead of EOF?
277 // But if so, we still need to deliver at least one EOF read to userspace.. right?
278 if (protocol_is_disconnected())
279 return 0;
280 if (!description.is_blocking())
281 return -EAGAIN;
282 }
283
284 if (!m_receive_queue.is_empty()) {
285 packet = m_receive_queue.take_first();
286 m_can_read = !m_receive_queue.is_empty();
287#ifdef IPV4_SOCKET_DEBUG
288 dbg() << "IPv4Socket(" << this << "): recvfrom without blocking " << packet.data.value().size() << " bytes, packets in queue: " << m_receive_queue.size_slow();
289#endif
290 }
291 }
292 if (!packet.data.has_value()) {
293 if (protocol_is_disconnected()) {
294 dbg() << "IPv4Socket{" << this << "} is protocol-disconnected, returning 0 in recvfrom!";
295 return 0;
296 }
297
298 locker.unlock();
299 auto res = Thread::current->block<Thread::ReadBlocker>(description);
300 locker.lock();
301
302 if (!m_can_read) {
303 if (res != Thread::BlockResult::WokeNormally)
304 return -EINTR;
305
306 // Unblocked due to timeout.
307 return -EAGAIN;
308 }
309 ASSERT(m_can_read);
310 ASSERT(!m_receive_queue.is_empty());
311 packet = m_receive_queue.take_first();
312 m_can_read = !m_receive_queue.is_empty();
313#ifdef IPV4_SOCKET_DEBUG
314 dbg() << "IPv4Socket(" << this << "): recvfrom with blocking " << packet.data.value().size() << " bytes, packets in queue: " << m_receive_queue.size_slow();
315#endif
316 }
317 ASSERT(packet.data.has_value());
318 auto& ipv4_packet = *(const IPv4Packet*)(packet.data.value().data());
319
320 if (addr) {
321#ifdef IPV4_SOCKET_DEBUG
322 dbg() << "Incoming packet is from: " << packet.peer_address << ":" << packet.peer_port;
323#endif
324 auto& ia = *(sockaddr_in*)addr;
325 memcpy(&ia.sin_addr, &packet.peer_address, sizeof(IPv4Address));
326 ia.sin_port = htons(packet.peer_port);
327 ia.sin_family = AF_INET;
328 ASSERT(addr_length);
329 *addr_length = sizeof(sockaddr_in);
330 }
331
332 if (type() == SOCK_RAW) {
333 ASSERT(buffer_length >= ipv4_packet.payload_size());
334 memcpy(buffer, ipv4_packet.payload(), ipv4_packet.payload_size());
335 return ipv4_packet.payload_size();
336 }
337
338 return protocol_receive(packet.data.value(), buffer, buffer_length, flags);
339}
340
341ssize_t IPv4Socket::recvfrom(FileDescription& description, void* buffer, size_t buffer_length, int flags, sockaddr* addr, socklen_t* addr_length)
342{
343 if (addr_length && *addr_length < sizeof(sockaddr_in))
344 return -EINVAL;
345
346#ifdef IPV4_SOCKET_DEBUG
347 klog() << "recvfrom: type=" << type() << ", local_port=" << local_port();
348#endif
349
350 ssize_t nreceived = 0;
351 if (buffer_mode() == BufferMode::Bytes)
352 nreceived = receive_byte_buffered(description, buffer, buffer_length, flags, addr, addr_length);
353 else
354 nreceived = receive_packet_buffered(description, buffer, buffer_length, flags, addr, addr_length);
355
356 if (nreceived > 0)
357 Thread::current->did_ipv4_socket_read(nreceived);
358 return nreceived;
359}
360
361bool IPv4Socket::did_receive(const IPv4Address& source_address, u16 source_port, KBuffer&& packet)
362{
363 LOCKER(lock());
364
365 if (is_shut_down_for_reading())
366 return false;
367
368 auto packet_size = packet.size();
369
370 if (buffer_mode() == BufferMode::Bytes) {
371 size_t space_in_receive_buffer = m_receive_buffer.space_for_writing();
372 if (packet_size > space_in_receive_buffer) {
373 dbg() << "IPv4Socket(" << this << "): did_receive refusing packet since buffer is full.";
374 ASSERT(m_can_read);
375 return false;
376 }
377 int nreceived = protocol_receive(packet, m_scratch_buffer.value().data(), m_scratch_buffer.value().size(), 0);
378 m_receive_buffer.write(m_scratch_buffer.value().data(), nreceived);
379 m_can_read = !m_receive_buffer.is_empty();
380 } else {
381 // FIXME: Maybe track the number of packets so we don't have to walk the entire packet queue to count them..
382 if (m_receive_queue.size_slow() > 2000) {
383 dbg() << "IPv4Socket(" << this << "): did_receive refusing packet since queue is full.";
384 return false;
385 }
386 m_receive_queue.append({ source_address, source_port, move(packet) });
387 m_can_read = true;
388 }
389 m_bytes_received += packet_size;
390#ifdef IPV4_SOCKET_DEBUG
391 if (buffer_mode() == BufferMode::Bytes)
392 dbg() << "IPv4Socket(" << this << "): did_receive " << packet_size << " bytes, total_received=" << m_bytes_received;
393 else
394 dbg() << "IPv4Socket(" << this << "): did_receive " << packet_size << " bytes, total_received=" << m_bytes_received << ", packets in queue: " << m_receive_queue.size_slow();
395#endif
396 return true;
397}
398
399String IPv4Socket::absolute_path(const FileDescription&) const
400{
401 if (m_role == Role::None)
402 return "socket";
403
404 StringBuilder builder;
405 builder.append("socket:");
406
407 builder.appendf("%s:%d", m_local_address.to_string().characters(), m_local_port);
408 if (m_role == Role::Accepted || m_role == Role::Connected)
409 builder.appendf(" / %s:%d", m_peer_address.to_string().characters(), m_peer_port);
410
411 switch (m_role) {
412 case Role::Listener:
413 builder.append(" (listening)");
414 break;
415 case Role::Accepted:
416 builder.append(" (accepted)");
417 break;
418 case Role::Connected:
419 builder.append(" (connected)");
420 break;
421 case Role::Connecting:
422 builder.append(" (connecting)");
423 break;
424 default:
425 ASSERT_NOT_REACHED();
426 }
427
428 return builder.to_string();
429}
430
431KResult IPv4Socket::setsockopt(int level, int option, const void* value, socklen_t value_size)
432{
433 if (level != IPPROTO_IP)
434 return Socket::setsockopt(level, option, value, value_size);
435
436 switch (option) {
437 case IP_TTL:
438 if (value_size < sizeof(int))
439 return KResult(-EINVAL);
440 if (*(const int*)value < 0 || *(const int*)value > 255)
441 return KResult(-EINVAL);
442 m_ttl = (u8) * (const int*)value;
443 return KSuccess;
444 default:
445 return KResult(-ENOPROTOOPT);
446 }
447}
448
449KResult IPv4Socket::getsockopt(FileDescription& description, int level, int option, void* value, socklen_t* value_size)
450{
451 if (level != IPPROTO_IP)
452 return Socket::getsockopt(description, level, option, value, value_size);
453
454 switch (option) {
455 case IP_TTL:
456 if (*value_size < sizeof(int))
457 return KResult(-EINVAL);
458 *(int*)value = m_ttl;
459 return KSuccess;
460 default:
461 return KResult(-ENOPROTOOPT);
462 }
463}
464
465int IPv4Socket::ioctl(FileDescription&, unsigned request, unsigned arg)
466{
467 REQUIRE_PROMISE(inet);
468
469 auto ioctl_route = [request, arg]() {
470 auto* route = (rtentry*)arg;
471 if (!Process::current->validate_read_typed(route))
472 return -EFAULT;
473
474 char namebuf[IFNAMSIZ + 1];
475 memcpy(namebuf, route->rt_dev, IFNAMSIZ);
476 namebuf[sizeof(namebuf) - 1] = '\0';
477
478 auto adapter = NetworkAdapter::lookup_by_name(namebuf);
479 if (!adapter)
480 return -ENODEV;
481
482 switch (request) {
483 case SIOCADDRT:
484 if (!Process::current->is_superuser())
485 return -EPERM;
486 if (route->rt_gateway.sa_family != AF_INET)
487 return -EAFNOSUPPORT;
488 if ((route->rt_flags & (RTF_UP | RTF_GATEWAY)) != (RTF_UP | RTF_GATEWAY))
489 return -EINVAL; // FIXME: Find the correct value to return
490 adapter->set_ipv4_gateway(IPv4Address(((sockaddr_in&)route->rt_gateway).sin_addr.s_addr));
491 return 0;
492
493 case SIOCDELRT:
494 // FIXME: Support gateway deletion
495 return 0;
496 }
497
498 return -EINVAL;
499 };
500
501 auto ioctl_interface = [request, arg]() {
502 auto* ifr = (ifreq*)arg;
503 if (!Process::current->validate_read_typed(ifr))
504 return -EFAULT;
505
506 char namebuf[IFNAMSIZ + 1];
507 memcpy(namebuf, ifr->ifr_name, IFNAMSIZ);
508 namebuf[sizeof(namebuf) - 1] = '\0';
509
510 auto adapter = NetworkAdapter::lookup_by_name(namebuf);
511 if (!adapter)
512 return -ENODEV;
513
514 switch (request) {
515 case SIOCSIFADDR:
516 if (!Process::current->is_superuser())
517 return -EPERM;
518 if (ifr->ifr_addr.sa_family != AF_INET)
519 return -EAFNOSUPPORT;
520 adapter->set_ipv4_address(IPv4Address(((sockaddr_in&)ifr->ifr_addr).sin_addr.s_addr));
521 return 0;
522
523 case SIOCSIFNETMASK:
524 if (!Process::current->is_superuser())
525 return -EPERM;
526 if (ifr->ifr_addr.sa_family != AF_INET)
527 return -EAFNOSUPPORT;
528 adapter->set_ipv4_netmask(IPv4Address(((sockaddr_in&)ifr->ifr_netmask).sin_addr.s_addr));
529 return 0;
530
531 case SIOCGIFADDR:
532 if (!Process::current->validate_write_typed(ifr))
533 return -EFAULT;
534 ifr->ifr_addr.sa_family = AF_INET;
535 ((sockaddr_in&)ifr->ifr_addr).sin_addr.s_addr = adapter->ipv4_address().to_u32();
536 return 0;
537
538 case SIOCGIFHWADDR:
539 if (!Process::current->validate_write_typed(ifr))
540 return -EFAULT;
541 ifr->ifr_hwaddr.sa_family = AF_INET;
542 {
543 auto mac_address = adapter->mac_address();
544 memcpy(ifr->ifr_hwaddr.sa_data, &mac_address, sizeof(MACAddress));
545 }
546 return 0;
547 }
548
549 return -EINVAL;
550 };
551
552 switch (request) {
553 case SIOCSIFADDR:
554 case SIOCSIFNETMASK:
555 case SIOCGIFADDR:
556 case SIOCGIFHWADDR:
557 return ioctl_interface();
558
559 case SIOCADDRT:
560 case SIOCDELRT:
561 return ioctl_route();
562 }
563
564 return -EINVAL;
565}
566
567void IPv4Socket::close()
568{
569 shutdown(SHUT_RDWR);
570}
571
572void IPv4Socket::shut_down_for_reading()
573{
574 Socket::shut_down_for_reading();
575 m_can_read = true;
576}
577
578}