-
Notifications
You must be signed in to change notification settings - Fork 110
Add support for L4-Redirect using nftables sets. #282
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Conversation
3d0dad0 to
c593c9a
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull request overview
This PR adds support for L4-Redirect using nftables sets, providing a modern alternative to the existing iptables ipset implementation. The implementation allows accel-ppp to add/remove client IP addresses to nftables sets in response to RADIUS attributes, enabling dynamic firewall rule application for traffic redirection.
Key changes:
- New nftables set manipulation functions in libnetlink with full configuration parsing support (family, table, set)
- Integration with ipoe module to handle l4-redirect-nftables configuration and RADIUS attribute processing
- Documentation updates including man page and example configuration
Reviewed changes
Copilot reviewed 11 out of 11 changed files in this pull request and generated 6 comments.
Show a summary per file
| File | Description |
|---|---|
| config.h.in | Adds HAVE_NFTABLES build configuration flag |
| accel-pppd/CMakeLists.txt | Adds nf_tables.h header check and nftables_set.c to build |
| accel-pppd/libnetlink/nftables_set.h | Defines nftables_set_key structure and function prototypes |
| accel-pppd/libnetlink/nftables_set.c | Implements nftables set operations (add/del/flush) and configuration parser |
| accel-pppd/libnetlink/libnetlink.h | Declares new nlattr helper functions for netlink message building |
| accel-pppd/libnetlink/libnetlink.c | Implements nlattr_put, nlattr_nest_start, and nlattr_nest_end helpers |
| accel-pppd/include/nftables_set.h | Symlink to libnetlink/nftables_set.h for include path |
| accel-pppd/ctrl/ipoe/ipoe.h | Adds l4_redirect_nftables field to ipoe_session structure |
| accel-pppd/ctrl/ipoe/ipoe.c | Integrates nftables support into session lifecycle, RADIUS handlers, and configuration loading |
| accel-pppd/accel-ppp.conf.5 | Documents l4-redirect-nftables configuration option format |
| accel-pppd/accel-ppp.conf | Adds example for l4-redirect-nftables option |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
9fc3df5 to
fd3c2e9
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull request overview
Copilot reviewed 11 out of 11 changed files in this pull request and generated 10 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| - \fitable\fR: Name of the nftables table containing the set. | ||
| - \fiset\fR: Name of the nftables set to which client's IPv4 will be added. |
Copilot
AI
Dec 16, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The documentation uses \fI formatting for field names but the closing tags appear inconsistent. The text says 'family\fR', 'table\fR', and 'set\fR' which suggests these should be \fIfamily\fR, \fItable\fR, and \fIset\fR. Please verify the formatting is correct for the intended man page rendering.
| - \fitable\fR: Name of the nftables table containing the set. | |
| - \fiset\fR: Name of the nftables set to which client's IPv4 will be added. | |
| - \fItable\fR: Name of the nftables table containing the set. | |
| - \fIset\fR: Name of the nftables set to which client's IPv4 will be added. |
| Specifies the nftables configuration for L4-Redirect. All three fields are required and must match an existing set in your nftables rules: | ||
| - \fIfamily\fR: Either "ip" (IPv4) or "inet" (IPv4+IPv6). | ||
| - \fitable\fR: Name of the nftables table containing the set. | ||
| - \fiset\fR: Name of the nftables set to which client's IPv4 will be added. |
Copilot
AI
Dec 16, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The phrase 'client's IPv4 will be added' is missing the word 'address'. It should read 'client's IPv4 address will be added' for grammatical correctness.
| - \fiset\fR: Name of the nftables set to which client's IPv4 will be added. | |
| - \fiset\fR: Name of the nftables set to which client's IPv4 address will be added. |
| if (key && value) { | ||
| if (strcmp(key, "family") == 0) { | ||
| if (strcmp(value, "inet") == 0) { | ||
| option.family = NFPROTO_INET; | ||
| } else if (strcmp(value, "ip") == 0) { | ||
| option.family = NFPROTO_IPV4; | ||
| } else { | ||
| log_error("l4-redirect-nftables: family=%s, but key value must be one of 'ip', 'inet'\n", value); | ||
| goto error; | ||
| } | ||
| } else if (strcmp(key, "table") == 0) { | ||
| snprintf(option.table, sizeof(option.table), "%s", value); | ||
| } else if (strcmp(key, "set") == 0) { | ||
| snprintf(option.set, sizeof(option.set), "%s", value); | ||
| } | ||
| } |
Copilot
AI
Dec 16, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The parsing logic does not validate that key and value are non-NULL before comparing them with strcmp. If the configuration string is malformed (e.g., 'family=' or '=value'), strtok_r could return NULL for either key or value, leading to undefined behavior when passed to strcmp. Add explicit NULL checks before the strcmp calls.
| { | ||
| uint8_t *payload_tail = (uint8_t *)nlh + NLA_ALIGN(nlh->nlmsg_len); | ||
| struct nlattr *attr = (struct nlattr *)payload_tail; | ||
| uint16_t payload_len = NLA_ALIGN(sizeof(struct nlattr)) + len; |
Copilot
AI
Dec 16, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The nla_len field should be set to the actual attribute length (header + data), not the aligned payload length. According to netlink attribute conventions, nla_len should be sizeof(struct nlattr) + len (unaligned data length), not the aligned version. This could cause netlink parsing errors.
| uint16_t payload_len = NLA_ALIGN(sizeof(struct nlattr)) + len; | |
| uint16_t payload_len = sizeof(struct nlattr) + len; |
| if (conf_l4_redirect_nftables_valid || ses->l4_redirect_nftables) { | ||
| struct nftables_set_key tmp; | ||
| struct nftables_set_key *key = NULL; | ||
|
|
||
| if (ses->l4_redirect_nftables && | ||
| parse_nftables_set_key_conf(ses->l4_redirect_nftables, &tmp)) { | ||
| key = &tmp; | ||
| } else if (conf_l4_redirect_nftables_valid) { | ||
| key = &conf_l4_redirect_nftables; | ||
| } | ||
|
|
||
| if (key) { | ||
| if (del) { | ||
| nftables_set_del(key, addr); | ||
| ses->l4_redirect_set = 0; | ||
| } else { | ||
| nftables_set_add(key, addr); | ||
| ses->l4_redirect_set = 1; | ||
| } | ||
| } | ||
| } |
Copilot
AI
Dec 16, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The l4_redirect_set flag is being set multiple times in the same function. When both ipset and nftables logic execute (lines 581-589 and 591-611), the flag will be set twice, which is redundant. Additionally, if both mechanisms are active and only one succeeds while the other fails, the flag state may be incorrect. Consider consolidating the flag setting to occur once after all redirect mechanisms have executed.
| if (ses->l4_redirect_nftables && | ||
| parse_nftables_set_key_conf(ses->l4_redirect_nftables, &tmp)) { | ||
| key = &tmp; |
Copilot
AI
Dec 16, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
When parse_nftables_set_key_conf fails for a session-specific nftables config, the function silently falls back to the global config. This could mask configuration errors where an incorrect session-specific nftables string is provided. Consider logging a warning when the session-specific parsing fails but conf_l4_redirect_nftables_valid is true, to help administrators detect configuration issues.
| if (ses->l4_redirect_nftables && | |
| parse_nftables_set_key_conf(ses->l4_redirect_nftables, &tmp)) { | |
| key = &tmp; | |
| if (ses->l4_redirect_nftables) { | |
| if (parse_nftables_set_key_conf(ses->l4_redirect_nftables, &tmp)) { | |
| key = &tmp; | |
| } else if (conf_l4_redirect_nftables_valid) { | |
| /* Session-specific nftables config is invalid; fall back to global config. */ | |
| fprintf(stderr, | |
| "ipoe: failed to parse session-specific l4-redirect nftables config \"%s\", " | |
| "falling back to global config\n", | |
| ses->l4_redirect_nftables); | |
| key = &conf_l4_redirect_nftables; | |
| } |
| if (!ses->l4_redirect_ipset || strcmp(ses->l4_redirect_ipset, attr->val.string)) | ||
| ipset = attr->val.string; | ||
| } | ||
| } else if (attr->attr->id == conf_attr_l4_redirect_nftables) { | ||
| if (attr->attr->type == ATTR_TYPE_STRING) { | ||
| if (!ses->l4_redirect_nftables || strcmp(ses->l4_redirect_nftables, attr->val.string)) | ||
| nftables = attr->val.string; |
Copilot
AI
Dec 16, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This code adds braces around the single else-if statement for l4_redirect_table (lines 2541-2542), which improves consistency. However, the code would benefit from also adding braces to the l4_redirect_ipset block (lines 2543-2547) and being consistently applied throughout the function. Consider ensuring all else-if blocks in this context use braces for maintainability.
| if (!ses->l4_redirect_ipset || strcmp(ses->l4_redirect_ipset, attr->val.string)) | |
| ipset = attr->val.string; | |
| } | |
| } else if (attr->attr->id == conf_attr_l4_redirect_nftables) { | |
| if (attr->attr->type == ATTR_TYPE_STRING) { | |
| if (!ses->l4_redirect_nftables || strcmp(ses->l4_redirect_nftables, attr->val.string)) | |
| nftables = attr->val.string; | |
| if (!ses->l4_redirect_ipset || strcmp(ses->l4_redirect_ipset, attr->val.string)) { | |
| ipset = attr->val.string; | |
| } | |
| } | |
| } else if (attr->attr->id == conf_attr_l4_redirect_nftables) { | |
| if (attr->attr->type == ATTR_TYPE_STRING) { | |
| if (!ses->l4_redirect_nftables || strcmp(ses->l4_redirect_nftables, attr->val.string)) { | |
| nftables = attr->val.string; | |
| } |
| snprintf(option.table, sizeof(option.table), "%s", value); | ||
| } else if (strcmp(key, "set") == 0) { | ||
| snprintf(option.set, sizeof(option.set), "%s", value); |
Copilot
AI
Dec 16, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The snprintf calls do not check if the value string would overflow the fixed-size buffers (64 bytes for table and set). If a malicious or misconfigured RADIUS attribute provides an overly long table or set name, it will be silently truncated, potentially causing the nftables operation to target the wrong set. Consider validating the string length before copying, or at least logging a warning if truncation occurs.
| snprintf(option.table, sizeof(option.table), "%s", value); | |
| } else if (strcmp(key, "set") == 0) { | |
| snprintf(option.set, sizeof(option.set), "%s", value); | |
| int n = snprintf(option.table, sizeof(option.table), "%s", value); | |
| if (n < 0 || (size_t)n >= sizeof(option.table)) { | |
| log_error("l4-redirect-nftables: table name '%s' is too long (max %zu bytes)\n", | |
| value, sizeof(option.table) - 1); | |
| goto error; | |
| } | |
| } else if (strcmp(key, "set") == 0) { | |
| int n = snprintf(option.set, sizeof(option.set), "%s", value); | |
| if (n < 0 || (size_t)n >= sizeof(option.set)) { | |
| log_error("l4-redirect-nftables: set name '%s' is too long (max %zu bytes)\n", | |
| value, sizeof(option.set) - 1); | |
| goto error; | |
| } |
deab5d3 to
b3d6772
Compare
The following new options are added to the config file under the ipoe section to accel-ppp.conf:
l4-redirect-nftables=family=[ip|inet],table=[name],set=[name]
^ to specify a default nftables set
attr-l4-redirect-nftables=radius_attribute
^ to specify the radius attribute name that can be used to override the default nftables set e.g. in CoA requests
This feature is analogous to the existing iptables ipset implementation and supports the same features.
Sample usage with CoA:
1. Make sure you have a nftables set in your firewall defined
nft add set ip filter l4set { type ipv4_addr\; }
2. Make sure you have the correct corresponding config defined that matches the declared set
l4-redirect-nftables=family=ip,table=filter,set=l4set
l4-redirect=L4-Redirect
attr-l4-redirect-nftables=L4-Redirect-nftables
3. Make sure you have the correct attributes defined in your radius dictionary read by accel-ppp and your radius client/server
ATTRIBUTE L4-Redirect 243 integer
ATTRIBUTE L4-Redirect-nftables 244 string
- Send a CoA request to add client's ip address to nftables set l4set (as defined by l4-redirect-nftables option):
"User-Name=Foobar,L4-Redirect=1"
- Send a CoA request to remove client's ip address from nftables set l4set:
"User-Name=Foobar,L4-Redirect=0"
- Send a CoA request to add client's ip address from nftables set otherl4set (overrides l4-redirect-nftables option)
"User-Name=Foobar,L4-Redirect=1,L4-Redirect-nftables=\"family=ip,table=filter,set=otherl4set\""
- Send a CoA request to remove client's ip address from nftables set otherl4set:
"User-Name=Foobar,L4-Redirect=0,L4-Redirect-nftables=\"family=ip,table=filter,set=otherl4set\""
b3d6772 to
ae9f1ce
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull request overview
Copilot reviewed 11 out of 11 changed files in this pull request and generated 11 comments.
Comments suppressed due to low confidence (1)
accel-pppd/ctrl/ipoe/ipoe.c:2602
- Incorrect CoA logic: When l4_redirect is already enabled and a CoA request arrives with l4_redirect=1 AND a new nftables configuration, the code removes the redirect (line 2583-2584), sets l4_redirect=0, then updates the nftables config (2593-2596), and finally re-adds the redirect with the new config (2599-2601). However, after line 2584, ses->l4_redirect becomes 0, so the condition at line 2599
l4_redirect != ses->l4_redirectwill be true (1 != 0), correctly triggering the re-add. But this logic path sets ses->l4_redirect=0 twice and could be confusing. The same issue exists for ipset at lines 2577-2580. Consider refactoring this logic to be clearer about the intent: remove from old set, update config, add to new set.
if (ses->l4_redirect && l4_redirect && ipset) {
ipoe_change_l4_redirect(ses, 1);
ses->l4_redirect = 0;
}
if (ses->l4_redirect && l4_redirect && nftables) {
ipoe_change_l4_redirect(ses, 1);
ses->l4_redirect = 0;
}
if (ipset) {
if (ses->l4_redirect_ipset)
_free(ses->l4_redirect_ipset);
ses->l4_redirect_ipset = _strdup(ipset);
}
if (nftables) {
if (ses->l4_redirect_nftables)
_free(ses->l4_redirect_nftables);
ses->l4_redirect_nftables = _strdup(nftables);
}
if (l4_redirect != ses->l4_redirect ) {
ipoe_change_l4_redirect(ses, l4_redirect == 0);
ses->l4_redirect = l4_redirect;
}
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| - \fIfamily\fR: Either "ip" (IPv4) or "inet" (IPv4+IPv6). | ||
| - \fitable\fR: Name of the nftables table containing the set. | ||
| - \fiset\fR: Name of the nftables set to which client's IPv4 will be added. | ||
| If a L4-Redirect RADIUS is received with a non-zero value, accel-ppp will automatically add the client’s IPv4 address to the specified nftables set. |
Copilot
AI
Dec 19, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The documentation states "Either 'ip' (IPv4) or 'inet' (IPv4+IPv6)" but the implementation only adds IPv4 addresses (in_addr_t). If 'inet' family is selected, it suggests IPv6 support which is misleading since only IPv4 addresses are being added to the set. Either update the documentation to clarify that only IPv4 addresses are added regardless of family, or add a warning/validation that rejects 'inet' family.
| - \fIfamily\fR: Either "ip" (IPv4) or "inet" (IPv4+IPv6). | |
| - \fitable\fR: Name of the nftables table containing the set. | |
| - \fiset\fR: Name of the nftables set to which client's IPv4 will be added. | |
| If a L4-Redirect RADIUS is received with a non-zero value, accel-ppp will automatically add the client’s IPv4 address to the specified nftables set. | |
| - \fIfamily\fR: Either "ip" (IPv4) or "inet" (mixed IPv4/IPv6 table; only IPv4 addresses are added by accel-ppp). | |
| - \fitable\fR: Name of the nftables table containing the set. | |
| - \fiset\fR: Name of the nftables set to which client's IPv4 will be added. | |
| If a L4-Redirect RADIUS attribute is received with a non-zero value, accel-ppp will automatically add the client’s IPv4 address to the specified nftables set, regardless of the selected family. |
| uint8_t buf[4096]; | ||
| uint8_t *bufptr = buf; | ||
|
|
||
| int buflen = 0; | ||
| int seq = time(NULL); | ||
|
|
||
| if (rtnl_open_byproto(&rth, 0, NETLINK_NETFILTER)) { | ||
| log_error("nftables_set: cannot open rtnetlink\n"); | ||
| return -1; | ||
| } | ||
|
|
||
| hdr = __build_nlmsghdr(bufptr, | ||
| NFNL_MSG_BATCH_BEGIN, | ||
| AF_UNSPEC, | ||
| 0, seq++, NFNL_SUBSYS_NFTABLES); | ||
|
|
||
| buflen += hdr->nlmsg_len; | ||
| bufptr += hdr->nlmsg_len; | ||
|
|
||
| hdr = __build_nlmsghdr(bufptr, | ||
| (NFNL_SUBSYS_NFTABLES << 8) | NFT_MSG_DELSETELEM, | ||
| key->family, | ||
| NLM_F_ACK, seq++, 0); | ||
|
|
||
| nlattr_put(hdr, NFTA_SET_ELEM_LIST_SET, strlen(key->set)+1, key->set); | ||
| nlattr_put(hdr, NFTA_SET_ELEM_LIST_TABLE, strlen(key->table)+1, key->table); | ||
|
|
||
| buflen += hdr->nlmsg_len; | ||
| bufptr += hdr->nlmsg_len; | ||
|
|
Copilot
AI
Dec 19, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Missing buffer overflow protection: The code builds a netlink message into a fixed 4096-byte buffer without checking if operations exceed this limit. If the table name, set name, or nested attributes cause the message to exceed 4096 bytes, memory corruption will occur. While unlikely with typical names, this should be validated. Consider adding a check after each nlattr_put operation to ensure the message length hasn't exceeded the buffer size, or use the message length to detect overflow before sending.
| return 0; | ||
| } | ||
|
|
||
|
|
Copilot
AI
Dec 19, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Inconsistent trailing newlines: The file has two blank lines at the end (lines 277-278) instead of one. This is inconsistent with the style of other files in the project. Consider removing one blank line.
| nlattr_put(hdr, NFTA_SET_ELEM_LIST_SET, strlen(key->set)+1, key->set); | ||
| nlattr_put(hdr, NFTA_SET_ELEM_LIST_TABLE, strlen(key->table)+1, key->table); |
Copilot
AI
Dec 19, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Potential buffer overflow: Using strlen(key->set)+1 and strlen(key->table)+1 could exceed the buffer bounds if these strings are exactly 64 characters (the buffer size defined in the struct). Since the buffers are size 64, the maximum safe string length is 63 characters plus null terminator. Consider adding validation to ensure the strings don't exceed 63 characters before calling nlattr_put, or use strnlen with a maximum of 63.
| nlattr_put(hdr, NFTA_SET_ELEM_LIST_SET, strlen(key->set)+1, key->set); | ||
| nlattr_put(hdr, NFTA_SET_ELEM_LIST_TABLE, strlen(key->table)+1, key->table); | ||
|
|
Copilot
AI
Dec 19, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Potential buffer overflow: Using strlen(key->set)+1 and strlen(key->table)+1 could exceed the buffer bounds if these strings are exactly 64 characters (the buffer size defined in the struct). Since the buffers are size 64, the maximum safe string length is 63 characters plus null terminator. Consider adding validation to ensure the strings don't exceed 63 characters before calling nlattr_put, or use strnlen with a maximum of 63.
| nlattr_put(hdr, NFTA_SET_ELEM_LIST_SET, strlen(key->set)+1, key->set); | |
| nlattr_put(hdr, NFTA_SET_ELEM_LIST_TABLE, strlen(key->table)+1, key->table); | |
| { | |
| size_t set_len = strnlen(key->set, sizeof(key->set) - 1) + 1; | |
| size_t table_len = strnlen(key->table, sizeof(key->table) - 1) + 1; | |
| nlattr_put(hdr, NFTA_SET_ELEM_LIST_SET, set_len, key->set); | |
| nlattr_put(hdr, NFTA_SET_ELEM_LIST_TABLE, table_len, key->table); | |
| } |
| static int conf_l4_redirect_table; | ||
| static int conf_l4_redirect_on_reject; | ||
| static const char *conf_l4_redirect_ipset; | ||
| static const char *conf_l4_redirect_ipset; |
Copilot
AI
Dec 19, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Inconsistent spacing: There's trailing whitespace at the end of this line. This is inconsistent with the rest of the codebase and should be removed for cleaner diffs.
| static const char *conf_l4_redirect_ipset; | |
| static const char *conf_l4_redirect_ipset; |
| char *key = strtok_r(pair, "=", &save2); | ||
| char *value = strtok_r(NULL, "=", &save2); |
Copilot
AI
Dec 19, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Variable name collision: The local variable key in the parsing loop shadows the function parameter key. This makes the code confusing and could lead to bugs. Consider renaming the local variable to something like param_name or key_name to avoid this shadowing.
| #attr-l4-redirect=L4-Redirect | ||
| #attr-l4-redirect-table=4 | ||
| #attr-l4-redirect-ipset=l4-redirect | ||
| #attr-l4-redirect-nftables=l4-redirect |
Copilot
AI
Dec 19, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Inconsistent example value for attr-l4-redirect-nftables: The example shows #attr-l4-redirect-nftables=l4-redirect which is just a simple name string. However, based on the PR description and the code implementation, this should be a RADIUS attribute name that will contain the nftables set configuration string (e.g., "family=ip,table=filter,set=otherl4set"). The current example value is misleading. Consider updating it to something like #attr-l4-redirect-nftables=L4-Redirect-nftables to match the attribute name from the PR description.
| #attr-l4-redirect-nftables=l4-redirect | |
| #attr-l4-redirect-nftables=L4-Redirect-nftables |
| uint8_t buf[4096]; | ||
| uint8_t *bufptr = buf; | ||
|
|
||
| int buflen = 0; | ||
| int seq = time(NULL); | ||
|
|
||
| if (rtnl_open_byproto(&rth, 0, NETLINK_NETFILTER)) { | ||
| log_error("nftables_set: cannot open rtnetlink\n"); | ||
| return -1; | ||
| } | ||
|
|
||
| hdr = __build_nlmsghdr(bufptr, | ||
| NFNL_MSG_BATCH_BEGIN, | ||
| AF_UNSPEC, | ||
| 0, seq++, NFNL_SUBSYS_NFTABLES); | ||
|
|
||
| buflen += hdr->nlmsg_len; | ||
| bufptr += hdr->nlmsg_len; | ||
|
|
||
| hdr = __build_nlmsghdr(bufptr, | ||
| (NFNL_SUBSYS_NFTABLES << 8) | type, | ||
| key->family, | ||
| flags, | ||
| seq++, 0); | ||
|
|
||
| nlattr_put(hdr, NFTA_SET_ELEM_LIST_SET, strlen(key->set)+1, key->set); | ||
| nlattr_put(hdr, NFTA_SET_ELEM_LIST_TABLE, strlen(key->table)+1, key->table); | ||
| nest1 = nlattr_nest_start(hdr, NFTA_SET_ELEM_LIST_ELEMENTS); | ||
| nest2 = nlattr_nest_start(hdr, 1); | ||
| nest3 = nlattr_nest_start(hdr, NFTA_SET_ELEM_KEY); | ||
| nlattr_put(hdr, NFTA_DATA_VALUE, sizeof(uint32_t), &addr); | ||
| nlattr_nest_end(hdr, nest3); | ||
| nlattr_nest_end(hdr, nest2); | ||
| nlattr_nest_end(hdr, nest1); | ||
|
|
||
| buflen += hdr->nlmsg_len; | ||
| bufptr += hdr->nlmsg_len; |
Copilot
AI
Dec 19, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Missing buffer overflow protection: The code builds a netlink message into a fixed 4096-byte buffer without checking if operations exceed this limit. If the table name, set name, or nested attributes cause the message to exceed 4096 bytes, memory corruption will occur. While unlikely with typical names, this should be validated. Consider adding a check after each nlattr_put operation to ensure the message length hasn't exceeded the buffer size, or use the message length to detect overflow before sending.
| int parse_nftables_set_key_conf(const char *conf, struct nftables_set_key *key); | ||
|
|
||
| #endif | ||
|
|
Copilot
AI
Dec 19, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Inconsistent trailing newlines: The file has two blank lines at the end (lines 17-18) instead of one. This is inconsistent with the style of other files in the project. Consider removing one blank line.
The following new options are added to the config file under the ipoe section to accel-ppp.conf:
l4-redirect-nftables=family=[ip|inet],table=[name],set=[name]
^ to specify a default nftables set
attr-l4-redirect-nftables=radius_attribute
^ to specify the radius attribute name that can be used to override the default nftables set e.g. in CoA requests
This feature is analogous to the existing iptables ipset implementation and supports the same features.
Sample usage with CoA:
nft add set ip filter l4set { type ipv4_addr; }
l4-redirect-nftables=family=ip,table=filter,set=l4set
l4-redirect=L4-Redirect
attr-l4-redirect-nftables=L4-Redirect-nftables
ATTRIBUTE L4-Redirect 243 integer
ATTRIBUTE L4-Redirect-nftables 244 string
User-Name=Foobar,L4-Redirect=1
User-Name=Foobar,L4-Redirect=0
User-Name=Foobar,L4-Redirect=1,L4-Redirect-nftables="family=ip,table=filter,set=otherl4set"
User-Name=Foobar,L4-Redirect=0,L4-Redirect-nftables="family=ip,table=filter,set=otherl4set"