summaryrefslogtreecommitdiff
path: root/Kernel
diff options
context:
space:
mode:
authorAndreas Kling <awesomekling@gmail.com>2019-09-19 21:40:06 +0200
committerAndreas Kling <awesomekling@gmail.com>2019-09-19 21:42:59 +0200
commit8cfb85936815a9de0fbfeeed1484f7f58ce8ea6d (patch)
treed1123e9b66a70eb1e593f8124198544f45ca01cd /Kernel
parent482d5295f1a490b76e3e888cdca9b393a26dda73 (diff)
downloadserenity-8cfb85936815a9de0fbfeeed1484f7f58ce8ea6d.zip
IPv4: Support overriding the default TTL (64)
Made getsockopt() and setsockopt() virtual so we can handle them in the various Socket subclasses. The subclasses map kinda nicely to "levels". This will allow us to implement things like "traceroute", although.. I spent some time trying to do that, but then hit a wall when it turned out that the user-mode networking in QEMU doesn't preserve TTL in the ICMP packets passing through.
Diffstat (limited to 'Kernel')
-rw-r--r--Kernel/Net/IPv4Socket.cpp37
-rw-r--r--Kernel/Net/IPv4Socket.h6
-rw-r--r--Kernel/Net/NetworkAdapter.cpp4
-rw-r--r--Kernel/Net/NetworkAdapter.h2
-rw-r--r--Kernel/Net/NetworkTask.cpp3
-rw-r--r--Kernel/Net/Socket.h4
-rw-r--r--Kernel/Net/TCPSocket.cpp4
-rw-r--r--Kernel/Net/UDPSocket.cpp2
-rw-r--r--Kernel/UnixTypes.h3
9 files changed, 55 insertions, 10 deletions
diff --git a/Kernel/Net/IPv4Socket.cpp b/Kernel/Net/IPv4Socket.cpp
index effbb89381..1b6951021b 100644
--- a/Kernel/Net/IPv4Socket.cpp
+++ b/Kernel/Net/IPv4Socket.cpp
@@ -195,7 +195,7 @@ ssize_t IPv4Socket::sendto(FileDescription&, const void* data, size_t data_lengt
#endif
if (type() == SOCK_RAW) {
- routing_decision.adapter->send_ipv4(routing_decision.next_hop, m_peer_address, (IPv4Protocol)protocol(), (const u8*)data, data_length);
+ routing_decision.adapter->send_ipv4(routing_decision.next_hop, m_peer_address, (IPv4Protocol)protocol(), (const u8*)data, data_length, m_ttl);
return data_length;
}
@@ -313,3 +313,38 @@ String IPv4Socket::absolute_path(const FileDescription&) const
return builder.to_string();
}
+
+KResult IPv4Socket::setsockopt(int level, int option, const void* value, socklen_t value_size)
+{
+ if (level != IPPROTO_IP)
+ return Socket::setsockopt(level, option, value, value_size);
+
+ switch (option) {
+ case IP_TTL:
+ if (value_size < sizeof(int))
+ return KResult(-EINVAL);
+ if (*(const int*)value < 0 || *(const int*)value > 255)
+ return KResult(-EINVAL);
+ m_ttl = (u8)*(const int*)value;
+ return KSuccess;
+ default:
+ return KResult(-ENOPROTOOPT);
+ }
+}
+
+KResult IPv4Socket::getsockopt(int level, int option, void* value, socklen_t* value_size)
+{
+ if (level != IPPROTO_IP)
+ return Socket::getsockopt(level, option, value, value_size);
+
+
+ switch (option) {
+ case IP_TTL:
+ if (*value_size < sizeof(int))
+ return KResult(-EINVAL);
+ *(int*)value = m_ttl;
+ return KSuccess;
+ default:
+ return KResult(-ENOPROTOOPT);
+ }
+}
diff --git a/Kernel/Net/IPv4Socket.h b/Kernel/Net/IPv4Socket.h
index ced971f1cf..2480634bee 100644
--- a/Kernel/Net/IPv4Socket.h
+++ b/Kernel/Net/IPv4Socket.h
@@ -31,6 +31,8 @@ public:
virtual bool can_write(FileDescription&) const override;
virtual ssize_t sendto(FileDescription&, const void*, size_t, int, const sockaddr*, socklen_t) override;
virtual ssize_t recvfrom(FileDescription&, void*, size_t, int flags, sockaddr*, socklen_t*) override;
+ virtual KResult setsockopt(int level, int option, const void*, socklen_t) override;
+ virtual KResult getsockopt(int level, int option, void*, socklen_t*) override;
void did_receive(const IPv4Address& peer_address, u16 peer_port, KBuffer&&);
@@ -47,6 +49,8 @@ public:
String absolute_path(const FileDescription& description) const override;
+ u8 ttl() const { return m_ttl; }
+
protected:
IPv4Socket(int type, int protocol);
virtual const char* class_name() const override { return "IPv4Socket"; }
@@ -83,5 +87,7 @@ private:
u32 m_bytes_received { 0 };
+ u8 m_ttl { 64 };
+
bool m_can_read { false };
};
diff --git a/Kernel/Net/NetworkAdapter.cpp b/Kernel/Net/NetworkAdapter.cpp
index 39cac3363c..9cba392b71 100644
--- a/Kernel/Net/NetworkAdapter.cpp
+++ b/Kernel/Net/NetworkAdapter.cpp
@@ -58,7 +58,7 @@ void NetworkAdapter::send(const MACAddress& destination, const ARPPacket& packet
send_raw((const u8*)eth, size_in_bytes);
}
-void NetworkAdapter::send_ipv4(const MACAddress& destination_mac, const IPv4Address& destination_ipv4, IPv4Protocol protocol, const u8* payload, size_t payload_size)
+void NetworkAdapter::send_ipv4(const MACAddress& destination_mac, const IPv4Address& destination_ipv4, IPv4Protocol protocol, const u8* payload, size_t payload_size, u8 ttl)
{
size_t size_in_bytes = sizeof(EthernetFrameHeader) + sizeof(IPv4Packet) + payload_size;
auto buffer = ByteBuffer::create_zeroed(size_in_bytes);
@@ -74,7 +74,7 @@ void NetworkAdapter::send_ipv4(const MACAddress& destination_mac, const IPv4Addr
ipv4.set_protocol((u8)protocol);
ipv4.set_length(sizeof(IPv4Packet) + payload_size);
ipv4.set_ident(1);
- ipv4.set_ttl(64);
+ ipv4.set_ttl(ttl);
ipv4.set_checksum(ipv4.compute_checksum());
m_packets_out++;
m_bytes_out += size_in_bytes;
diff --git a/Kernel/Net/NetworkAdapter.h b/Kernel/Net/NetworkAdapter.h
index b063163eed..9f145870b9 100644
--- a/Kernel/Net/NetworkAdapter.h
+++ b/Kernel/Net/NetworkAdapter.h
@@ -34,7 +34,7 @@ public:
void set_ipv4_gateway(const IPv4Address&);
void send(const MACAddress&, const ARPPacket&);
- void send_ipv4(const MACAddress&, const IPv4Address&, IPv4Protocol, const u8* payload, size_t payload_size);
+ void send_ipv4(const MACAddress&, const IPv4Address&, IPv4Protocol, const u8* payload, size_t payload_size, u8 ttl);
Optional<KBuffer> dequeue_packet();
diff --git a/Kernel/Net/NetworkTask.cpp b/Kernel/Net/NetworkTask.cpp
index f5b404fcd8..bce343364f 100644
--- a/Kernel/Net/NetworkTask.cpp
+++ b/Kernel/Net/NetworkTask.cpp
@@ -272,7 +272,8 @@ void handle_icmp(const EthernetFrameHeader& eth, const IPv4Packet& ipv4_packet)
if (size_t icmp_payload_size = icmp_packet_size - sizeof(ICMPEchoPacket))
memcpy(response.payload(), request.payload(), icmp_payload_size);
response.header.set_checksum(internet_checksum(&response, icmp_packet_size));
- adapter->send_ipv4(eth.source(), ipv4_packet.source(), IPv4Protocol::ICMP, buffer.data(), buffer.size());
+ // FIXME: What is the right TTL value here? Is 64 ok? Should we use the same TTL as the echo request?
+ adapter->send_ipv4(eth.source(), ipv4_packet.source(), IPv4Protocol::ICMP, buffer.data(), buffer.size(), 64);
}
}
diff --git a/Kernel/Net/Socket.h b/Kernel/Net/Socket.h
index 98a3d221f5..c297aa8e7b 100644
--- a/Kernel/Net/Socket.h
+++ b/Kernel/Net/Socket.h
@@ -76,8 +76,8 @@ public:
virtual ssize_t sendto(FileDescription&, const void*, size_t, int flags, const sockaddr*, socklen_t) = 0;
virtual ssize_t recvfrom(FileDescription&, void*, size_t, int flags, sockaddr*, socklen_t*) = 0;
- KResult setsockopt(int level, int option, const void*, socklen_t);
- KResult getsockopt(int level, int option, void*, socklen_t*);
+ virtual KResult setsockopt(int level, int option, const void*, socklen_t);
+ virtual KResult getsockopt(int level, int option, void*, socklen_t*);
pid_t origin_pid() const { return m_origin_pid; }
pid_t acceptor_pid() const { return m_acceptor_pid; }
diff --git a/Kernel/Net/TCPSocket.cpp b/Kernel/Net/TCPSocket.cpp
index 8f3c15cb5e..8be47ed526 100644
--- a/Kernel/Net/TCPSocket.cpp
+++ b/Kernel/Net/TCPSocket.cpp
@@ -170,7 +170,7 @@ void TCPSocket::send_tcp_packet(u16 flags, const void* payload, int payload_size
routing_decision.adapter->send_ipv4(
routing_decision.next_hop, peer_address(), IPv4Protocol::TCP,
- buffer.data(), buffer.size());
+ buffer.data(), buffer.size(), ttl());
m_packets_out++;
m_bytes_out += buffer.size();
@@ -210,7 +210,7 @@ void TCPSocket::send_outgoing_packets()
#endif
routing_decision.adapter->send_ipv4(
routing_decision.next_hop, peer_address(), IPv4Protocol::TCP,
- packet.buffer.data(), packet.buffer.size());
+ packet.buffer.data(), packet.buffer.size(), ttl());
m_packets_out++;
m_bytes_out += packet.buffer.size();
diff --git a/Kernel/Net/UDPSocket.cpp b/Kernel/Net/UDPSocket.cpp
index da6f6d140f..103c824226 100644
--- a/Kernel/Net/UDPSocket.cpp
+++ b/Kernel/Net/UDPSocket.cpp
@@ -77,7 +77,7 @@ int UDPSocket::protocol_send(const void* data, int data_length)
local_port(),
peer_address().to_string().characters(),
peer_port());
- routing_decision.adapter->send_ipv4(routing_decision.next_hop, peer_address(), IPv4Protocol::UDP, buffer.data(), buffer.size());
+ routing_decision.adapter->send_ipv4(routing_decision.next_hop, peer_address(), IPv4Protocol::UDP, buffer.data(), buffer.size(), ttl());
return data_length;
}
diff --git a/Kernel/UnixTypes.h b/Kernel/UnixTypes.h
index d23b48251c..34047f2916 100644
--- a/Kernel/UnixTypes.h
+++ b/Kernel/UnixTypes.h
@@ -337,10 +337,13 @@ struct pollfd {
#define SO_KEEPALIVE 3
#define SO_ERROR 4
+#define IPPROTO_IP 0
#define IPPROTO_ICMP 1
#define IPPROTO_TCP 6
#define IPPROTO_UDP 17
+#define IP_TTL 2
+
struct sockaddr {
u16 sa_family;
char sa_data[14];