@@ -1233,52 +1233,63 @@ static unsigned int get_ifa_flags(struct ifaddrmsg *ifa,
ifa->ifa_flags;
}
-/* Mapping from argument to address flag mask */
-static const struct {
+/* Mapping from argument to address flag mask and attributes */
+static const struct ifa_flag_data_t {
const char *name;
- unsigned long value;
-} ifa_flag_names[] = {
- { "secondary", IFA_F_SECONDARY },
- { "temporary", IFA_F_SECONDARY },
- { "nodad", IFA_F_NODAD },
- { "optimistic", IFA_F_OPTIMISTIC },
- { "dadfailed", IFA_F_DADFAILED },
- { "home", IFA_F_HOMEADDRESS },
- { "deprecated", IFA_F_DEPRECATED },
- { "tentative", IFA_F_TENTATIVE },
- { "permanent", IFA_F_PERMANENT },
- { "mngtmpaddr", IFA_F_MANAGETEMPADDR },
- { "noprefixroute", IFA_F_NOPREFIXROUTE },
- { "autojoin", IFA_F_MCAUTOJOIN },
- { "stable-privacy", IFA_F_STABLE_PRIVACY },
+ unsigned long mask;
+ bool readonly;
+ bool v6only;
+} ifa_flag_data[] = {
+ { .name = "secondary", .mask = IFA_F_SECONDARY, .readonly = true, .v6only = false},
+ { .name = "temporary", .mask = IFA_F_SECONDARY, .readonly = true, .v6only = false},
+ { .name = "nodad", .mask = IFA_F_NODAD, .readonly = false, .v6only = true},
+ { .name = "optimistic", .mask = IFA_F_OPTIMISTIC, .readonly = true, .v6only = true},
+ { .name = "dadfailed", .mask = IFA_F_DADFAILED, .readonly = true, .v6only = true},
+ { .name = "home", .mask = IFA_F_HOMEADDRESS, .readonly = false, .v6only = true},
+ { .name = "deprecated", .mask = IFA_F_DEPRECATED, .readonly = true, .v6only = true},
+ { .name = "tentative", .mask = IFA_F_TENTATIVE, .readonly = true, .v6only = true},
+ { .name = "permanent", .mask = IFA_F_PERMANENT, .readonly = true, .v6only = true},
+ { .name = "mngtmpaddr", .mask = IFA_F_MANAGETEMPADDR, .readonly = false, .v6only = true},
+ { .name = "noprefixroute", .mask = IFA_F_NOPREFIXROUTE, .readonly = false, .v6only = true},
+ { .name = "autojoin", .mask = IFA_F_MCAUTOJOIN, .readonly = false, .v6only = true},
+ { .name = "stable-privacy", .mask = IFA_F_STABLE_PRIVACY, .readonly = true, .v6only = true},
};
+/* Returns a pointer to the data structure for a particular interface flag, or null if no flag could be found */
+static const struct ifa_flag_data_t* lookup_flag_data_by_name(const char* flag_name) {
+ for (int i = 0; i < ARRAY_SIZE(ifa_flag_data); ++i) {
+ if (strcmp(flag_name, ifa_flag_data[i].name) == 0)
+ return &ifa_flag_data[i];
+ }
+ return NULL;
+}
+
static void print_ifa_flags(FILE *fp, const struct ifaddrmsg *ifa,
unsigned int flags)
{
unsigned int i;
- for (i = 0; i < ARRAY_SIZE(ifa_flag_names); i++) {
- unsigned long mask = ifa_flag_names[i].value;
+ for (i = 0; i < ARRAY_SIZE(ifa_flag_data); i++) {
+ const struct ifa_flag_data_t* flag_data = &ifa_flag_data[i];
- if (mask == IFA_F_PERMANENT) {
- if (!(flags & mask))
+ if (flag_data->mask == IFA_F_PERMANENT) {
+ if (!(flags & flag_data->mask))
print_bool(PRINT_ANY,
"dynamic", "dynamic ", true);
- } else if (flags & mask) {
- if (mask == IFA_F_SECONDARY &&
+ } else if (flags & flag_data->mask) {
+ if (flag_data->mask == IFA_F_SECONDARY &&
ifa->ifa_family == AF_INET6) {
print_bool(PRINT_ANY,
"temporary", "temporary ", true);
} else {
print_string(PRINT_FP, NULL,
- "%s ", ifa_flag_names[i].name);
+ "%s ", flag_data->name);
print_bool(PRINT_JSON,
- ifa_flag_names[i].name, NULL, true);
+ flag_data->name, NULL, true);
}
}
- flags &= ~mask;
+ flags &= ~flag_data->mask;
}
if (flags) {
@@ -1297,7 +1308,6 @@ static void print_ifa_flags(FILE *fp, const struct ifaddrmsg *ifa,
static int get_filter(const char *arg)
{
bool inv = false;
- unsigned int i;
if (arg[0] == '-') {
inv = true;
@@ -1313,18 +1323,16 @@ static int get_filter(const char *arg)
arg = "secondary";
}
- for (i = 0; i < ARRAY_SIZE(ifa_flag_names); i++) {
- if (strcmp(arg, ifa_flag_names[i].name))
- continue;
+ const struct ifa_flag_data_t* flag_data = lookup_flag_data_by_name(arg);
+ if (flag_data == NULL)
+ return -1;
- if (inv)
- filter.flags &= ~ifa_flag_names[i].value;
- else
- filter.flags |= ifa_flag_names[i].value;
- filter.flagmask |= ifa_flag_names[i].value;
- return 0;
- }
- return -1;
+ if (inv)
+ filter.flags &= ~flag_data->mask;
+ else
+ filter.flags |= flag_data->mask;
+ filter.flagmask |= flag_data->mask;
+ return 0;
}
static int ifa_label_match_rta(int ifindex, const struct rtattr *rta)
@@ -2330,25 +2338,15 @@ static int ipaddr_modify(int cmd, int flags, int argc, char **argv)
preferred_lftp = *argv;
if (set_lifetime(&preferred_lft, *argv))
invarg("preferred_lft value", *argv);
- } else if (strcmp(*argv, "home") == 0) {
- if (req.ifa.ifa_family == AF_INET6)
- ifa_flags |= IFA_F_HOMEADDRESS;
- else
- fprintf(stderr, "Warning: home option can be set only for IPv6 addresses\n");
- } else if (strcmp(*argv, "nodad") == 0) {
- if (req.ifa.ifa_family == AF_INET6)
- ifa_flags |= IFA_F_NODAD;
- else
- fprintf(stderr, "Warning: nodad option can be set only for IPv6 addresses\n");
- } else if (strcmp(*argv, "mngtmpaddr") == 0) {
- if (req.ifa.ifa_family == AF_INET6)
- ifa_flags |= IFA_F_MANAGETEMPADDR;
- else
- fprintf(stderr, "Warning: mngtmpaddr option can be set only for IPv6 addresses\n");
- } else if (strcmp(*argv, "noprefixroute") == 0) {
- ifa_flags |= IFA_F_NOPREFIXROUTE;
- } else if (strcmp(*argv, "autojoin") == 0) {
- ifa_flags |= IFA_F_MCAUTOJOIN;
+ } else if (lookup_flag_data_by_name(*argv)) {
+ const struct ifa_flag_data_t* flag_data = lookup_flag_data_by_name(*argv);
+ if (flag_data->readonly) {
+ fprintf(stderr, "Warning: %s option is not mutable from userspace\n", flag_data->name);
+ } else if (flag_data->v6only && req.ifa.ifa_family != AF_INET6) {
+ fprintf(stderr, "Warning: %s option can be set only for IPv6 addresses\n", flag_data->name);
+ } else {
+ ifa_flags |= flag_data->mask;
+ }
} else {
if (strcmp(*argv, "local") == 0)
NEXT_ARG();