aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMaxim Sobolev <sobomax@FreeBSD.org>2021-10-07 20:41:40 +0000
committerMaxim Sobolev <sobomax@FreeBSD.org>2021-10-15 23:48:12 +0000
commit461e6f23db3b9794e6af88b381b066a2c0463d1c (patch)
treeb09f0cd4644828149c9574e617445785afbd0851
parentfc393054398ea50fb0cee52704e9385afe888b48 (diff)
downloadsrc-461e6f23db3b9794e6af88b381b066a2c0463d1c.tar.gz
src-461e6f23db3b9794e6af88b381b066a2c0463d1c.zip
Fix fragmented UDP packets handling since rev.360967.
Consider IP_MF flag when checking length of the UDP packet to match the declared value. Sponsored by: Sippy Software, Inc. Differential Revision: https://reviews.freebsd.org/D32363 MFC after: 2 weeks
-rw-r--r--sys/netinet/libalias/alias.c225
1 files changed, 120 insertions, 105 deletions
diff --git a/sys/netinet/libalias/alias.c b/sys/netinet/libalias/alias.c
index 39e9b060623d..37f5bd5a1db1 100644
--- a/sys/netinet/libalias/alias.c
+++ b/sys/netinet/libalias/alias.c
@@ -721,21 +721,37 @@ ProtoAliasOut(struct libalias *la, struct ip *pip,
return (PKT_ALIAS_IGNORED);
}
+#define MF_ISSET(_pip) (ntohs((_pip)->ip_off) & IP_MF)
+#define FRAG_NO_HDR(_pip) (ntohs((_pip)->ip_off) & IP_OFFMASK)
+
+static struct udphdr *
+ValidateUdpLength(struct ip *pip)
+{
+ struct udphdr *ud;
+ size_t dlen;
+
+#ifdef _KERNEL
+ KASSERT(!FRAG_NO_HDR(pip), ("header-less fragment isn't expected here"));
+#endif
+ dlen = ntohs(pip->ip_len) - (pip->ip_hl << 2);
+ if (dlen < sizeof(struct udphdr))
+ return (NULL);
+ ud = (struct udphdr *)ip_next(pip);
+ if (!MF_ISSET(pip) && dlen < ntohs(ud->uh_ulen))
+ return (NULL);
+ return (ud);
+}
+
static int
UdpAliasIn(struct libalias *la, struct ip *pip)
{
struct udphdr *ud;
struct alias_link *lnk;
- size_t dlen;
LIBALIAS_LOCK_ASSERT(la);
- dlen = ntohs(pip->ip_len) - (pip->ip_hl << 2);
- if (dlen < sizeof(struct udphdr))
- return (PKT_ALIAS_IGNORED);
-
- ud = (struct udphdr *)ip_next(pip);
- if (dlen < ntohs(ud->uh_ulen))
+ ud = ValidateUdpLength(pip);
+ if (ud == NULL)
return (PKT_ALIAS_IGNORED);
lnk = FindUdpTcpIn(la, pip->ip_src, pip->ip_dst,
@@ -828,19 +844,14 @@ UdpAliasOut(struct libalias *la, struct ip *pip, int maxpacketsize, int create)
u_short proxy_server_port;
int proxy_type;
int error;
- size_t dlen;
LIBALIAS_LOCK_ASSERT(la);
- /* Return if proxy-only mode is enabled and not proxyrule found.*/
- dlen = ntohs(pip->ip_len) - (pip->ip_hl << 2);
- if (dlen < sizeof(struct udphdr))
- return (PKT_ALIAS_IGNORED);
-
- ud = (struct udphdr *)ip_next(pip);
- if (dlen < ntohs(ud->uh_ulen))
+ ud = ValidateUdpLength(pip);
+ if (ud == NULL)
return (PKT_ALIAS_IGNORED);
+ /* Return if proxy-only mode is enabled and not proxyrule found.*/
proxy_type = ProxyCheck(la, &proxy_server_address, &proxy_server_port,
pip->ip_src, pip->ip_dst, ud->uh_dport, pip->ip_p);
if (proxy_type == 0 && (la->packetAliasMode & PKT_ALIAS_PROXY_ONLY))
@@ -1339,64 +1350,65 @@ LibAliasInLocked(struct libalias *la, struct ip *pip, int maxpacketsize)
goto getout;
}
+ if (FRAG_NO_HDR(pip)) {
+ iresult = FragmentIn(la, pip->ip_src, pip, pip->ip_id,
+ &pip->ip_sum);
+ goto getout;
+ }
+
iresult = PKT_ALIAS_IGNORED;
- if ((ntohs(pip->ip_off) & IP_OFFMASK) == 0) {
- switch (pip->ip_p) {
- case IPPROTO_ICMP:
- iresult = IcmpAliasIn(la, pip);
- break;
- case IPPROTO_UDP:
- iresult = UdpAliasIn(la, pip);
- break;
- case IPPROTO_TCP:
- iresult = TcpAliasIn(la, pip);
- break;
+ switch (pip->ip_p) {
+ case IPPROTO_ICMP:
+ iresult = IcmpAliasIn(la, pip);
+ break;
+ case IPPROTO_UDP:
+ iresult = UdpAliasIn(la, pip);
+ break;
+ case IPPROTO_TCP:
+ iresult = TcpAliasIn(la, pip);
+ break;
#ifdef _KERNEL
- case IPPROTO_SCTP:
- iresult = SctpAlias(la, pip, SN_TO_LOCAL);
- break;
+ case IPPROTO_SCTP:
+ iresult = SctpAlias(la, pip, SN_TO_LOCAL);
+ break;
#endif
- case IPPROTO_GRE: {
- int error;
- struct alias_data ad = {
- .lnk = NULL,
- .oaddr = NULL,
- .aaddr = NULL,
- .aport = NULL,
- .sport = NULL,
- .dport = NULL,
- .maxpktsize = 0
- };
-
- /* Walk out chain. */
- error = find_handler(IN, IP, la, pip, &ad);
- if (error == 0)
- iresult = PKT_ALIAS_OK;
- else
- iresult = ProtoAliasIn(la, pip->ip_src,
- pip, pip->ip_p, &pip->ip_sum);
- break;
- }
- default:
- iresult = ProtoAliasIn(la, pip->ip_src, pip,
- pip->ip_p, &pip->ip_sum);
- break;
- }
+ case IPPROTO_GRE: {
+ int error;
+ struct alias_data ad = {
+ .lnk = NULL,
+ .oaddr = NULL,
+ .aaddr = NULL,
+ .aport = NULL,
+ .sport = NULL,
+ .dport = NULL,
+ .maxpktsize = 0
+ };
- if (ntohs(pip->ip_off) & IP_MF) {
- struct alias_link *lnk;
+ /* Walk out chain. */
+ error = find_handler(IN, IP, la, pip, &ad);
+ if (error == 0)
+ iresult = PKT_ALIAS_OK;
+ else
+ iresult = ProtoAliasIn(la, pip->ip_src,
+ pip, pip->ip_p, &pip->ip_sum);
+ break;
+ }
+ default:
+ iresult = ProtoAliasIn(la, pip->ip_src, pip,
+ pip->ip_p, &pip->ip_sum);
+ break;
+ }
- lnk = FindFragmentIn1(la, pip->ip_src, alias_addr, pip->ip_id);
- if (lnk != NULL) {
- iresult = PKT_ALIAS_FOUND_HEADER_FRAGMENT;
- SetFragmentAddr(lnk, pip->ip_dst);
- } else {
- iresult = PKT_ALIAS_ERROR;
- }
+ if (MF_ISSET(pip)) {
+ struct alias_link *lnk;
+
+ lnk = FindFragmentIn1(la, pip->ip_src, alias_addr, pip->ip_id);
+ if (lnk != NULL) {
+ iresult = PKT_ALIAS_FOUND_HEADER_FRAGMENT;
+ SetFragmentAddr(lnk, pip->ip_dst);
+ } else {
+ iresult = PKT_ALIAS_ERROR;
}
- } else {
- iresult = FragmentIn(la, pip->ip_src, pip, pip->ip_id,
- &pip->ip_sum);
}
getout:
@@ -1492,52 +1504,55 @@ LibAliasOutLocked(struct libalias *la,
} else if (la->packetAliasMode & PKT_ALIAS_PROXY_ONLY) {
SetDefaultAliasAddress(la, pip->ip_src);
}
+
+ if (FRAG_NO_HDR(pip)) {
+ iresult = FragmentOut(la, pip, &pip->ip_sum);
+ goto getout_restore;
+ }
+
iresult = PKT_ALIAS_IGNORED;
- if ((ntohs(pip->ip_off) & IP_OFFMASK) == 0) {
- switch (pip->ip_p) {
- case IPPROTO_ICMP:
- iresult = IcmpAliasOut(la, pip, create);
- break;
- case IPPROTO_UDP:
- iresult = UdpAliasOut(la, pip, maxpacketsize, create);
- break;
- case IPPROTO_TCP:
- iresult = TcpAliasOut(la, pip, maxpacketsize, create);
- break;
+ switch (pip->ip_p) {
+ case IPPROTO_ICMP:
+ iresult = IcmpAliasOut(la, pip, create);
+ break;
+ case IPPROTO_UDP:
+ iresult = UdpAliasOut(la, pip, maxpacketsize, create);
+ break;
+ case IPPROTO_TCP:
+ iresult = TcpAliasOut(la, pip, maxpacketsize, create);
+ break;
#ifdef _KERNEL
- case IPPROTO_SCTP:
- iresult = SctpAlias(la, pip, SN_TO_GLOBAL);
- break;
+ case IPPROTO_SCTP:
+ iresult = SctpAlias(la, pip, SN_TO_GLOBAL);
+ break;
#endif
- case IPPROTO_GRE: {
- int error;
- struct alias_data ad = {
- .lnk = NULL,
- .oaddr = NULL,
- .aaddr = NULL,
- .aport = NULL,
- .sport = NULL,
- .dport = NULL,
- .maxpktsize = 0
- };
- /* Walk out chain. */
- error = find_handler(OUT, IP, la, pip, &ad);
- if (error == 0)
- iresult = PKT_ALIAS_OK;
- else
- iresult = ProtoAliasOut(la, pip,
- pip->ip_dst, pip->ip_p, &pip->ip_sum, create);
- break;
- }
- default:
+ case IPPROTO_GRE: {
+ int error;
+ struct alias_data ad = {
+ .lnk = NULL,
+ .oaddr = NULL,
+ .aaddr = NULL,
+ .aport = NULL,
+ .sport = NULL,
+ .dport = NULL,
+ .maxpktsize = 0
+ };
+ /* Walk out chain. */
+ error = find_handler(OUT, IP, la, pip, &ad);
+ if (error == 0)
+ iresult = PKT_ALIAS_OK;
+ else
iresult = ProtoAliasOut(la, pip,
pip->ip_dst, pip->ip_p, &pip->ip_sum, create);
- break;
+ break;
}
- } else {
- iresult = FragmentOut(la, pip, &pip->ip_sum);
+ default:
+ iresult = ProtoAliasOut(la, pip,
+ pip->ip_dst, pip->ip_p, &pip->ip_sum, create);
+ break;
}
+getout_restore:
SetDefaultAliasAddress(la, addr_save);
getout:
return (iresult);