Skip to content

Commit

Permalink
mac/gw.hpp: refactor MacGatewayInfo implementation
Browse files Browse the repository at this point in the history
In order simplify and to make it work for "add bypass route" functionality:

 - remove RTA_NETMASK flag. This is only needed to get the netmask
that applies to the route. For the purposes of getting the next-hop
gateway and netmask of the specific interface it is not needed. Moreover,
with this flag set by some reasons I got the default gateway instead of
specific host route.

 - remove OPENVPN_NEXTADDR(6) macros. Plain assignment and explicit length
adjustment is is cleaner.

 - remove memset, since brace initialization is enough.

 - define variables close to usage instead of at the top.

Signed-off-by: Lev Stipakov <[email protected]>
  • Loading branch information
lstipakov committed Oct 10, 2024
1 parent 7459a2a commit 09697ef
Showing 1 changed file with 32 additions and 64 deletions.
96 changes: 32 additions & 64 deletions openvpn/tun/mac/gw.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -59,29 +59,12 @@ class MacGatewayInfo
char m_space[512];
};

#define OPENVPN_ROUNDUP(a) \
((a) > 0 ? (1 + (((a)-1) | (sizeof(std::uint32_t) - 1))) : sizeof(std::uint32_t))

#define OPENVPN_NEXTADDR(w, u) \
if (rtm_addrs & (w)) \
{ \
l = OPENVPN_ROUNDUP(u.sin_len); \
std::memmove(cp, &(u), l); \
cp += l; \
}


#define OPENVPN_NEXTADDR6(w, u) \
if (rtm_addrs & (w)) \
{ \
l = OPENVPN_ROUNDUP(u.sin6_len); \
std::memmove(cp, &(u), l); \
cp += l; \
constexpr std::uint32_t openvpn_roundup(std::uint32_t a)
{
constexpr std::uint32_t size = sizeof(std::uint32_t);
return a > 0 ? (1 + ((a - 1) | (size - 1))) : size;
}

#define OPENVPN_ADVANCE(x, n) \
(x += OPENVPN_ROUNDUP((n)->sa_len))

public:
OPENVPN_EXCEPTION(route_gateway_error);

Expand All @@ -95,81 +78,70 @@ class MacGatewayInfo

MacGatewayInfo(IP::Addr dest)
{
struct rtmsg m_rtmsg;
ScopedFD sockfd;
int seq, l, pid, rtm_addrs;
sockaddr_in so_dst{}, so_mask{};
sockaddr_in6 so_dst6{};
char *cp = m_rtmsg.m_space;
struct sockaddr *gate = nullptr, *ifp = nullptr, *sa;
struct rt_msghdr *rtm_aux;

/* setup data to send to routing socket */
pid = ::getpid();
seq = 0;
rtm_addrs = RTA_DST | RTA_NETMASK | RTA_IFP;
int seq = 0;

std::memset(&m_rtmsg, 0, sizeof(m_rtmsg));
std::memset(&m_rtmsg.m_rtm, 0, sizeof(struct rt_msghdr));
struct rtmsg m_rtmsg
{
};

m_rtmsg.m_rtm.rtm_type = RTM_GET;
m_rtmsg.m_rtm.rtm_flags = RTF_UP | RTF_GATEWAY;
m_rtmsg.m_rtm.rtm_flags = RTF_UP;
m_rtmsg.m_rtm.rtm_version = RTM_VERSION;
m_rtmsg.m_rtm.rtm_seq = ++seq;
m_rtmsg.m_rtm.rtm_addrs = rtm_addrs;

const bool ipv6 = dest.is_ipv6();
m_rtmsg.m_rtm.rtm_addrs = RTA_DST | RTA_GATEWAY | RTA_IFP;
m_rtmsg.m_rtm.rtm_msglen = sizeof(struct rt_msghdr);

if (!ipv6)
if (!dest.is_ipv6())
{
so_dst = dest.to_ipv4().to_sockaddr();
// 32 netmask to lookup the route to the destination
so_mask.sin_family = AF_INET;
so_mask.sin_addr.s_addr = 0xffffffff;
so_mask.sin_len = sizeof(struct sockaddr_in);

OPENVPN_NEXTADDR(RTA_DST, so_dst);
OPENVPN_NEXTADDR(RTA_NETMASK, so_mask);
auto dst4 = reinterpret_cast<sockaddr_in *>(&m_rtmsg.m_space);
*dst4 = dest.to_ipv4().to_sockaddr();

m_rtmsg.m_rtm.rtm_msglen += openvpn_roundup(sizeof(struct sockaddr_in));
}
else
{
so_dst6 = dest.to_ipv6().to_sockaddr();
OPENVPN_NEXTADDR6(RTA_DST, so_dst6);
}
auto dst6 = reinterpret_cast<sockaddr_in6 *>(&m_rtmsg.m_space);
*dst6 = dest.to_ipv6().to_sockaddr();

m_rtmsg.m_rtm.rtm_msglen = l = cp - (char *)&m_rtmsg;
m_rtmsg.m_rtm.rtm_msglen += openvpn_roundup(sizeof(struct sockaddr_in6));
}

/* transact with routing socket */
ScopedFD sockfd;
sockfd.reset(socket(PF_ROUTE, SOCK_RAW, 0));
if (!sockfd.defined())
throw route_gateway_error("GDG: socket #1 failed");

auto ret = ::write(sockfd(), (char *)&m_rtmsg, l);
auto ret = ::write(sockfd(), &m_rtmsg, m_rtmsg.m_rtm.rtm_msglen);

This comment has been minimized.

Copy link
@savely-krasovsky

savely-krasovsky Nov 7, 2024

@lstipakov do you have any ideas why we could get here this error after updating to 3.10.3?

route_gateway_error: GDG: problem writing to routing socket: -1 errno: 3 msg: No such process

This comment has been minimized.

Copy link
@savely-krasovsky

savely-krasovsky Nov 7, 2024

Created an issue:
#344

if (ret < 0)
throw route_gateway_error("GDG: problem writing to routing socket: " + std::to_string(ret)
+ " errno: " + std::to_string(errno) + " msg: " + ::strerror(errno));

int l = 0;
int pid = ::getpid();
do
{
l = ::read(sockfd(), (char *)&m_rtmsg, sizeof(m_rtmsg));
l = ::read(sockfd(), &m_rtmsg, sizeof(m_rtmsg));
} while (l > 0 && (m_rtmsg.m_rtm.rtm_seq != seq || m_rtmsg.m_rtm.rtm_pid != pid));
sockfd.close();

/* extract return data from routing socket */
rtm_aux = &m_rtmsg.m_rtm;
cp = ((char *)(rtm_aux + 1));
struct sockaddr *gate = nullptr, *ifp = nullptr, *sa;
struct rt_msghdr *rtm_aux = &m_rtmsg.m_rtm;
auto cp = reinterpret_cast<char *>(rtm_aux + 1);
if (rtm_aux->rtm_addrs)
{
for (unsigned int i = 1; i; i <<= 1u)
{
if (i & rtm_aux->rtm_addrs)
{
sa = (struct sockaddr *)cp;
sa = reinterpret_cast<struct sockaddr *>(cp);
if (i == RTA_GATEWAY)
gate = sa;
else if (i == RTA_IFP)
ifp = sa;
OPENVPN_ADVANCE(cp, sa);
cp += openvpn_roundup(sa->sa_len);
}
}
}
Expand All @@ -187,7 +159,7 @@ class MacGatewayInfo
if (ifp)
{
/* get interface name */
const struct sockaddr_dl *adl = (struct sockaddr_dl *)ifp;
const auto adl = reinterpret_cast<struct sockaddr_dl *>(ifp);
const size_t len = adl->sdl_nlen;
if (len && len < sizeof(iface_))
{
Expand Down Expand Up @@ -245,18 +217,14 @@ class MacGatewayInfo
&& ifa->ifa_addr->sa_family == AF_LINK
&& !strncmp(ifa->ifa_name, iface_, IFNAMSIZ))
{
const struct sockaddr_dl *sockaddr_dl = reinterpret_cast<struct sockaddr_dl *>(ifa->ifa_addr);
const auto sockaddr_dl = reinterpret_cast<struct sockaddr_dl *>(ifa->ifa_addr);

hwaddr_.reset(reinterpret_cast<unsigned char *>(LLADDR(sockaddr_dl)));
flags_ |= HWADDR_DEFINED;
}
}
}
}
#undef OPENVPN_ROUNDUP
#undef OPENVPN_NEXTADDR
#undef OPENVPN_NEXTADDR6
#undef OPENVPN_ADVANCE

std::string info() const
{
Expand Down

0 comments on commit 09697ef

Please sign in to comment.