better with obs forms
[ghsmtp.git] / Sock.cpp
blob7fb93f678ca386d4d77e219e8b59ac7a88918c3e
1 #include "Sock.hpp"
3 #include "IP4.hpp"
4 #include "IP6.hpp"
6 #include <glog/logging.h>
8 static bool is_ipv4_mapped_ipv6_addresses(in6_addr const& sa)
10 // clang-format off
11 return sa.s6_addr[0] == 0 &&
12 sa.s6_addr[1] == 0 &&
13 sa.s6_addr[2] == 0 &&
14 sa.s6_addr[3] == 0 &&
15 sa.s6_addr[4] == 0 &&
16 sa.s6_addr[5] == 0 &&
17 sa.s6_addr[6] == 0 &&
18 sa.s6_addr[7] == 0 &&
19 sa.s6_addr[8] == 0 &&
20 sa.s6_addr[9] == 0 &&
21 sa.s6_addr[10] == 0xff &&
22 sa.s6_addr[11] == 0xff;
23 // clang-format on
26 Sock::Sock(int fd_in,
27 int fd_out,
28 std::function<void(void)> read_hook,
29 std::chrono::milliseconds read_timeout,
30 std::chrono::milliseconds write_timeout,
31 std::chrono::milliseconds starttls_timeout)
32 : iostream_(
33 fd_in, fd_out, read_hook, read_timeout, write_timeout, starttls_timeout)
35 // Get our local IP address as "us".
37 if (-1 == getsockname(fd_in, &us_addr_.addr, &us_addr_len_)) {
38 // Ignore ENOTSOCK errors from getsockname, useful for testing.
39 PLOG_IF(WARNING, ENOTSOCK != errno) << "getsockname failed";
41 else {
42 switch (us_addr_len_) {
43 case sizeof(sockaddr_in):
44 PCHECK(inet_ntop(AF_INET, &us_addr_.addr_in.sin_addr, us_addr_str_,
45 sizeof us_addr_str_)
46 != nullptr);
47 us_address_literal_ = IP4::to_address_literal(us_addr_str_);
48 break;
49 case sizeof(sockaddr_in6):
50 PCHECK(inet_ntop(AF_INET6, &us_addr_.addr_in6.sin6_addr, us_addr_str_,
51 sizeof us_addr_str_)
52 != nullptr);
53 us_address_literal_ = IP6::to_address_literal(us_addr_str_);
54 break;
55 default:
56 LOG(FATAL) << "bogus address length (" << us_addr_len_
57 << ") returned from getsockname";
61 // Get the remote IP address as "them".
63 if (-1 == getpeername(fd_out, &them_addr_.addr, &them_addr_len_)) {
64 // Ignore ENOTSOCK errors from getpeername, useful for testing.
65 PLOG_IF(WARNING, ENOTSOCK != errno) << "getpeername failed";
67 else {
68 switch (them_addr_len_) {
69 case sizeof(sockaddr_in):
70 PCHECK(inet_ntop(AF_INET, &them_addr_.addr_in.sin_addr, them_addr_str_,
71 sizeof them_addr_str_)
72 != nullptr);
73 them_address_literal_ = IP4::to_address_literal(them_addr_str_);
74 break;
76 case sizeof(sockaddr_in6):
77 if (is_ipv4_mapped_ipv6_addresses(them_addr_.addr_in6.sin6_addr)) {
78 PCHECK(inet_ntop(AF_INET, &them_addr_.addr_in6.sin6_addr.s6_addr[12],
79 them_addr_str_, sizeof them_addr_str_)
80 != nullptr);
81 them_address_literal_ = IP4::to_address_literal(them_addr_str_);
82 // LOG(INFO) << "IPv4 disguised as IPv6: " << them_addr_str_;
84 else {
85 PCHECK(inet_ntop(AF_INET6, &them_addr_.addr_in6.sin6_addr,
86 them_addr_str_, sizeof them_addr_str_)
87 != nullptr);
88 them_address_literal_ = IP6::to_address_literal(them_addr_str_);
90 break;
92 default:
93 LOG(FATAL) << "bogus address length (" << them_addr_len_
94 << ") returned from getpeername";