mirror of
https://gitlab.com/apparmor/apparmor.git
synced 2025-03-04 08:24:42 +01:00
parser: add fine grained conditionals to network rule
Options available are ip= and port= inside the peer group or outside, representing local addresses and ports: network peer=(ip=127.0.0.1 port=8080), network ip=::1 port=8080 peer=(ip=::2 port=8081), The 'ip' option supports both IPv4 and IPv6. Examples would be ip=192.168.0.4, or ip=::578d The 'port' option accepts a 16-bit unsigned integer. An example would be port=1234 Signed-off-by: Georgia Garcia <georgia.garcia@canonical.com>
This commit is contained in:
parent
746f76d3e1
commit
ddefe11a40
4 changed files with 267 additions and 34 deletions
|
@ -83,7 +83,7 @@ void all_rule::add_implied_rules(Profile &prof)
|
||||||
(void) rule->add_prefix(*prefix);
|
(void) rule->add_prefix(*prefix);
|
||||||
prof.rule_ents.push_back(rule);
|
prof.rule_ents.push_back(rule);
|
||||||
|
|
||||||
rule = new network_rule(0, NULL);
|
rule = new network_rule(0, (struct cond_entry *)NULL, (struct cond_entry *)NULL);
|
||||||
(void) rule->add_prefix(*prefix);
|
(void) rule->add_prefix(*prefix);
|
||||||
prof.rule_ents.push_back(rule);
|
prof.rule_ents.push_back(rule);
|
||||||
|
|
||||||
|
|
|
@ -20,6 +20,7 @@
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
#include <map>
|
#include <map>
|
||||||
|
#include <arpa/inet.h>
|
||||||
|
|
||||||
#include "lib.h"
|
#include "lib.h"
|
||||||
#include "parser.h"
|
#include "parser.h"
|
||||||
|
@ -298,7 +299,59 @@ const struct network_tuple *net_find_mapping(const struct network_tuple *map,
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
void network_rule::move_conditionals(struct cond_entry *conds)
|
bool parse_ipv4_address(const char *input, struct ip_address *result)
|
||||||
|
{
|
||||||
|
struct in_addr addr;
|
||||||
|
if (inet_pton(AF_INET, input, &addr) == 1) {
|
||||||
|
result->family = AF_INET;
|
||||||
|
result->address.address_v4 = addr.s_addr;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool parse_ipv6_address(const char *input, struct ip_address *result)
|
||||||
|
{
|
||||||
|
struct in6_addr addr;
|
||||||
|
if (inet_pton(AF_INET6, input, &addr) == 1) {
|
||||||
|
result->family = AF_INET6;
|
||||||
|
memcpy(result->address.address_v6, addr.s6_addr, 16);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool parse_ip(const char *ip, struct ip_address *result)
|
||||||
|
{
|
||||||
|
return parse_ipv6_address(ip, result) ||
|
||||||
|
parse_ipv4_address(ip, result);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool parse_port_number(const char *port_entry, uint16_t *port) {
|
||||||
|
char *eptr;
|
||||||
|
unsigned long port_tmp = strtoul(port_entry, &eptr, 10);
|
||||||
|
|
||||||
|
if (port_tmp >= 0 && port_entry != eptr &&
|
||||||
|
*eptr == '\0' && port_tmp <= UINT16_MAX) {
|
||||||
|
*port = port_tmp;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool network_rule::parse_port(ip_conds &entry)
|
||||||
|
{
|
||||||
|
entry.is_port = true;
|
||||||
|
return parse_port_number(entry.sport, &entry.port);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool network_rule::parse_address(ip_conds &entry)
|
||||||
|
{
|
||||||
|
entry.is_ip = true;
|
||||||
|
return parse_ip(entry.sip, &entry.ip);
|
||||||
|
}
|
||||||
|
|
||||||
|
void network_rule::move_conditionals(struct cond_entry *conds, ip_conds &ip_cond)
|
||||||
{
|
{
|
||||||
struct cond_entry *cond_ent;
|
struct cond_entry *cond_ent;
|
||||||
|
|
||||||
|
@ -306,10 +359,18 @@ void network_rule::move_conditionals(struct cond_entry *conds)
|
||||||
/* for now disallow keyword 'in' (list) */
|
/* for now disallow keyword 'in' (list) */
|
||||||
if (!cond_ent->eq)
|
if (!cond_ent->eq)
|
||||||
yyerror("keyword \"in\" is not allowed in network rules\n");
|
yyerror("keyword \"in\" is not allowed in network rules\n");
|
||||||
|
if (strcmp(cond_ent->name, "ip") == 0) {
|
||||||
/* no valid conditionals atm */
|
move_conditional_value("network", &ip_cond.sip, cond_ent);
|
||||||
yyerror("invalid network rule conditional \"%s\"\n",
|
if (!parse_address(ip_cond))
|
||||||
cond_ent->name);
|
yyerror("network invalid ip='%s'\n", ip_cond.sip);
|
||||||
|
} else if (strcmp(cond_ent->name, "port") == 0) {
|
||||||
|
move_conditional_value("network", &ip_cond.sport, cond_ent);
|
||||||
|
if (!parse_port(ip_cond))
|
||||||
|
yyerror("network invalid port='%s'\n", ip_cond.sport);
|
||||||
|
} else {
|
||||||
|
yyerror("invalid network rule conditional \"%s\"\n",
|
||||||
|
cond_ent->name);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -322,7 +383,8 @@ void network_rule::set_netperm(unsigned int family, unsigned int type)
|
||||||
network_perms[family] |= 1 << type;
|
network_perms[family] |= 1 << type;
|
||||||
}
|
}
|
||||||
|
|
||||||
network_rule::network_rule(perms_t perms_p, struct cond_entry *conds):
|
network_rule::network_rule(perms_t perms_p, struct cond_entry *conds,
|
||||||
|
struct cond_entry *peer_conds):
|
||||||
dedup_perms_rule_t(AA_CLASS_NETV8)
|
dedup_perms_rule_t(AA_CLASS_NETV8)
|
||||||
{
|
{
|
||||||
size_t family_index;
|
size_t family_index;
|
||||||
|
@ -331,21 +393,25 @@ network_rule::network_rule(perms_t perms_p, struct cond_entry *conds):
|
||||||
set_netperm(family_index, 0xFFFFFFFF);
|
set_netperm(family_index, 0xFFFFFFFF);
|
||||||
}
|
}
|
||||||
|
|
||||||
move_conditionals(conds);
|
move_conditionals(conds, local);
|
||||||
|
move_conditionals(peer_conds, peer);
|
||||||
free_cond_list(conds);
|
free_cond_list(conds);
|
||||||
|
free_cond_list(peer_conds);
|
||||||
|
|
||||||
if (perms_p) {
|
if (perms_p) {
|
||||||
perms = perms_p;
|
perms = perms_p;
|
||||||
if (perms & ~AA_VALID_NET_PERMS)
|
if (perms & ~AA_VALID_NET_PERMS)
|
||||||
yyerror("perms contains invalid permissions for network rules\n");
|
yyerror("perms contains invalid permissions for network rules\n");
|
||||||
/* can conds change permission availability? */
|
else if ((perms & ~AA_PEER_NET_PERMS) && has_peer_conds())
|
||||||
|
yyerror("network 'create', 'shutdown', 'setattr', 'getattr', 'bind', 'listen', 'setopt', and/or 'getopt' accesses cannot be used with peer socket conditionals\n");
|
||||||
} else {
|
} else {
|
||||||
perms = AA_VALID_NET_PERMS;
|
perms = AA_VALID_NET_PERMS;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
network_rule::network_rule(perms_t perms_p, const char *family, const char *type,
|
network_rule::network_rule(perms_t perms_p, const char *family, const char *type,
|
||||||
const char *protocol, struct cond_entry *conds):
|
const char *protocol, struct cond_entry *conds,
|
||||||
|
struct cond_entry *peer_conds):
|
||||||
dedup_perms_rule_t(AA_CLASS_NETV8)
|
dedup_perms_rule_t(AA_CLASS_NETV8)
|
||||||
{
|
{
|
||||||
const struct network_tuple *mapping = NULL;
|
const struct network_tuple *mapping = NULL;
|
||||||
|
@ -364,14 +430,17 @@ network_rule::network_rule(perms_t perms_p, const char *family, const char *type
|
||||||
if (network_map.empty())
|
if (network_map.empty())
|
||||||
yyerror(_("Invalid network entry."));
|
yyerror(_("Invalid network entry."));
|
||||||
|
|
||||||
move_conditionals(conds);
|
move_conditionals(conds, local);
|
||||||
|
move_conditionals(peer_conds, peer);
|
||||||
free_cond_list(conds);
|
free_cond_list(conds);
|
||||||
|
free_cond_list(peer_conds);
|
||||||
|
|
||||||
if (perms_p) {
|
if (perms_p) {
|
||||||
perms = perms_p;
|
perms = perms_p;
|
||||||
if (perms & ~AA_VALID_NET_PERMS)
|
if (perms & ~AA_VALID_NET_PERMS)
|
||||||
yyerror("perms contains invalid permissions for network rules\n");
|
yyerror("perms contains invalid permissions for network rules\n");
|
||||||
/* can conds change permission availability? */
|
else if ((perms & ~AA_PEER_NET_PERMS) && has_peer_conds())
|
||||||
|
yyerror("network 'create', 'shutdown', 'setattr', 'getattr', 'bind', 'listen', 'setopt', and/or 'getopt' accesses cannot be used with peer socket conditionals\n");
|
||||||
} else {
|
} else {
|
||||||
perms = AA_VALID_NET_PERMS;
|
perms = AA_VALID_NET_PERMS;
|
||||||
}
|
}
|
||||||
|
@ -387,7 +456,8 @@ network_rule::network_rule(perms_t perms_p, unsigned int family, unsigned int ty
|
||||||
perms = perms_p;
|
perms = perms_p;
|
||||||
if (perms & ~AA_VALID_NET_PERMS)
|
if (perms & ~AA_VALID_NET_PERMS)
|
||||||
yyerror("perms contains invalid permissions for network rules\n");
|
yyerror("perms contains invalid permissions for network rules\n");
|
||||||
/* can conds change permission availability? */
|
else if ((perms & ~AA_PEER_NET_PERMS) && has_peer_conds())
|
||||||
|
yyerror("network 'create', 'shutdown', 'setattr', 'getattr', 'bind', 'listen', 'setopt', and/or 'getopt' accesses cannot be used with peer socket conditionals\n");
|
||||||
} else {
|
} else {
|
||||||
perms = AA_VALID_NET_PERMS;
|
perms = AA_VALID_NET_PERMS;
|
||||||
}
|
}
|
||||||
|
@ -455,6 +525,79 @@ void network_rule::warn_once(const char *name)
|
||||||
rule_t::warn_once(name, "network rules not enforced");
|
rule_t::warn_once(name, "network rules not enforced");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string gen_ip_cond(const struct ip_address ip)
|
||||||
|
{
|
||||||
|
std::ostringstream oss;
|
||||||
|
int i;
|
||||||
|
if (ip.family == AF_INET) {
|
||||||
|
/* add a byte containing the size of the following ip */
|
||||||
|
oss << "\\x04";
|
||||||
|
|
||||||
|
u8 *byte = (u8 *) &ip.address.address_v4; /* in network byte order */
|
||||||
|
for (i = 0; i < 4; i++)
|
||||||
|
oss << "\\x" << std::setfill('0') << std::setw(2) << std::hex << static_cast<unsigned int>(byte[i]);
|
||||||
|
} else {
|
||||||
|
/* add a byte containing the size of the following ip */
|
||||||
|
oss << "\\x10";
|
||||||
|
for (i = 0; i < 16; ++i)
|
||||||
|
oss << "\\x" << std::setfill('0') << std::setw(2) << std::hex << static_cast<unsigned int>(ip.address.address_v6[i]);
|
||||||
|
}
|
||||||
|
return oss.str();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string gen_port_cond(uint16_t port)
|
||||||
|
{
|
||||||
|
std::ostringstream oss;
|
||||||
|
if (port > 0) {
|
||||||
|
oss << "\\x" << std::setfill('0') << std::setw(2) << std::hex << ((port & 0xff00) >> 8);
|
||||||
|
oss << "\\x" << std::setfill('0') << std::setw(2) << std::hex << (port & 0xff);
|
||||||
|
} else {
|
||||||
|
oss << "..";
|
||||||
|
}
|
||||||
|
return oss.str();
|
||||||
|
}
|
||||||
|
|
||||||
|
void network_rule::gen_ip_conds(std::ostringstream &oss, ip_conds entry, bool is_peer, bool is_cmd)
|
||||||
|
{
|
||||||
|
/* encode protocol */
|
||||||
|
if (!is_cmd) {
|
||||||
|
if (entry.is_ip) {
|
||||||
|
oss << "\\x" << std::setfill('0') << std::setw(2) << std::hex << ((entry.ip.family & 0xff00) >> 8);
|
||||||
|
oss << "\\x" << std::setfill('0') << std::setw(2) << std::hex << (entry.ip.family & 0xff);
|
||||||
|
} else {
|
||||||
|
oss << "..";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (entry.is_port) {
|
||||||
|
/* encode port type (privileged - 1, remote - 2, unprivileged - 0) */
|
||||||
|
if (!is_peer && perms & AA_NET_BIND && entry.port < IPPORT_RESERVED)
|
||||||
|
oss << "\\x01";
|
||||||
|
else if (is_peer)
|
||||||
|
oss << "\\x02";
|
||||||
|
else
|
||||||
|
oss << "\\x00";
|
||||||
|
|
||||||
|
oss << gen_port_cond(entry.port);
|
||||||
|
} else {
|
||||||
|
/* port type + port number */
|
||||||
|
if (!is_cmd)
|
||||||
|
oss << ".";
|
||||||
|
oss << "..";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (entry.is_ip) {
|
||||||
|
oss << gen_ip_cond(entry.ip);
|
||||||
|
} else {
|
||||||
|
/* encode 0 to indicate there's no ip (ip size) */
|
||||||
|
oss << "\\x00";
|
||||||
|
}
|
||||||
|
|
||||||
|
oss << "\\-x01"; /* oob separator */
|
||||||
|
oss << default_match_pattern; /* label - not used for now */
|
||||||
|
oss << "\\x00"; /* null transition */
|
||||||
|
}
|
||||||
|
|
||||||
bool network_rule::gen_net_rule(Profile &prof, u16 family, unsigned int type_mask) {
|
bool network_rule::gen_net_rule(Profile &prof, u16 family, unsigned int type_mask) {
|
||||||
std::ostringstream buffer;
|
std::ostringstream buffer;
|
||||||
std::string buf;
|
std::string buf;
|
||||||
|
@ -468,13 +611,50 @@ bool network_rule::gen_net_rule(Profile &prof, u16 family, unsigned int type_mas
|
||||||
buffer << "\\x" << std::setfill('0') << std::setw(2) << std::hex << ((type_mask & 0xff00) >> 8);
|
buffer << "\\x" << std::setfill('0') << std::setw(2) << std::hex << ((type_mask & 0xff00) >> 8);
|
||||||
buffer << "\\x" << std::setfill('0') << std::setw(2) << std::hex << (type_mask & 0xff);
|
buffer << "\\x" << std::setfill('0') << std::setw(2) << std::hex << (type_mask & 0xff);
|
||||||
}
|
}
|
||||||
buf = buffer.str();
|
|
||||||
|
|
||||||
if (!prof.policy.rules->add_rule(buf.c_str(), rule_mode == RULE_DENY, map_perms(AA_VALID_NET_PERMS),
|
if (perms & AA_PEER_NET_PERMS) {
|
||||||
dedup_perms_rule_t::audit == AUDIT_FORCE ? map_perms(AA_VALID_NET_PERMS) : 0,
|
gen_ip_conds(buffer, peer, true, false);
|
||||||
parseopts))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
|
buffer << "\\x" << std::setfill('0') << std::setw(2) << std::hex << CMD_ADDR;
|
||||||
|
|
||||||
|
gen_ip_conds(buffer, local, false, true);
|
||||||
|
|
||||||
|
buf = buffer.str();
|
||||||
|
if (!prof.policy.rules->add_rule(buf.c_str(), rule_mode == RULE_DENY, map_perms(perms),
|
||||||
|
dedup_perms_rule_t::audit == AUDIT_FORCE ? map_perms(perms) : 0,
|
||||||
|
parseopts))
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if ((perms & AA_NET_LISTEN) || (perms & AA_NET_OPT)) {
|
||||||
|
gen_ip_conds(buffer, local, false, false);
|
||||||
|
|
||||||
|
if (perms & AA_NET_LISTEN) {
|
||||||
|
std::ostringstream cmd_buffer;
|
||||||
|
cmd_buffer << buffer.str();
|
||||||
|
cmd_buffer << "\\x" << std::setfill('0') << std::setw(2) << std::hex << CMD_LISTEN;
|
||||||
|
/* length of queue allowed - not used for now */
|
||||||
|
cmd_buffer << "..";
|
||||||
|
buf = cmd_buffer.str();
|
||||||
|
if (!prof.policy.rules->add_rule(buf.c_str(), rule_mode == RULE_DENY, map_perms(perms),
|
||||||
|
dedup_perms_rule_t::audit == AUDIT_FORCE ? map_perms(perms) : 0,
|
||||||
|
parseopts))
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (perms & AA_NET_OPT) {
|
||||||
|
std::ostringstream cmd_buffer;
|
||||||
|
cmd_buffer << buffer.str();
|
||||||
|
cmd_buffer << "\\x" << std::setfill('0') << std::setw(2) << std::hex << CMD_OPT;
|
||||||
|
/* level - not used for now */
|
||||||
|
cmd_buffer << "..";
|
||||||
|
/* socket mapping - not used for now */
|
||||||
|
cmd_buffer << "..";
|
||||||
|
buf = cmd_buffer.str();
|
||||||
|
if (!prof.policy.rules->add_rule(buf.c_str(), rule_mode == RULE_DENY, map_perms(perms),
|
||||||
|
dedup_perms_rule_t::audit == AUDIT_FORCE ? map_perms(perms) : 0,
|
||||||
|
parseopts))
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -75,6 +75,10 @@
|
||||||
#define AA_PEER_NET_PERMS (AA_VALID_NET_PERMS & (~AA_LOCAL_NET_PERMS | \
|
#define AA_PEER_NET_PERMS (AA_VALID_NET_PERMS & (~AA_LOCAL_NET_PERMS | \
|
||||||
AA_NET_ACCEPT))
|
AA_NET_ACCEPT))
|
||||||
|
|
||||||
|
#define CMD_ADDR 1
|
||||||
|
#define CMD_LISTEN 2
|
||||||
|
#define CMD_OPT 4
|
||||||
|
|
||||||
struct network_tuple {
|
struct network_tuple {
|
||||||
const char *family_name;
|
const char *family_name;
|
||||||
unsigned int family;
|
unsigned int family;
|
||||||
|
@ -104,22 +108,58 @@ int net_find_type_val(const char *type);
|
||||||
const char *net_find_type_name(int type);
|
const char *net_find_type_name(int type);
|
||||||
const char *net_find_af_name(unsigned int af);
|
const char *net_find_af_name(unsigned int af);
|
||||||
|
|
||||||
|
struct ip_address {
|
||||||
|
union {
|
||||||
|
uint8_t address_v6[16];
|
||||||
|
uint32_t address_v4;
|
||||||
|
} address;
|
||||||
|
uint16_t family;
|
||||||
|
};
|
||||||
|
|
||||||
|
class ip_conds {
|
||||||
|
public:
|
||||||
|
char *sip = NULL;
|
||||||
|
char *sport = NULL;
|
||||||
|
|
||||||
|
bool is_ip = false;
|
||||||
|
bool is_port = false;
|
||||||
|
|
||||||
|
uint16_t port;
|
||||||
|
struct ip_address ip;
|
||||||
|
|
||||||
|
void free_conds() {
|
||||||
|
if (sip)
|
||||||
|
free(sip);
|
||||||
|
if (sport)
|
||||||
|
free(sport);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
class network_rule: public dedup_perms_rule_t {
|
class network_rule: public dedup_perms_rule_t {
|
||||||
void move_conditionals(struct cond_entry *conds);
|
void move_conditionals(struct cond_entry *conds, ip_conds &ip_cond);
|
||||||
public:
|
public:
|
||||||
std::unordered_map<unsigned int, std::vector<struct aa_network_entry>> network_map;
|
std::unordered_map<unsigned int, std::vector<struct aa_network_entry>> network_map;
|
||||||
std::unordered_map<unsigned int, perms_t> network_perms;
|
std::unordered_map<unsigned int, perms_t> network_perms;
|
||||||
|
|
||||||
|
ip_conds peer;
|
||||||
|
ip_conds local;
|
||||||
|
|
||||||
|
bool has_local_conds(void) { return local.sip || local.sport; }
|
||||||
|
bool has_peer_conds(void) { return peer.sip || peer.sport; }
|
||||||
/* empty constructor used only for the profile to access
|
/* empty constructor used only for the profile to access
|
||||||
* static elements to maintain compatibility with
|
* static elements to maintain compatibility with
|
||||||
* AA_CLASS_NET */
|
* AA_CLASS_NET */
|
||||||
network_rule(): dedup_perms_rule_t(AA_CLASS_NETV8) { }
|
network_rule(): dedup_perms_rule_t(AA_CLASS_NETV8) { }
|
||||||
network_rule(perms_t perms_p, struct cond_entry *conds);
|
network_rule(perms_t perms_p, struct cond_entry *conds,
|
||||||
|
struct cond_entry *peer_conds);
|
||||||
network_rule(perms_t perms_p, const char *family, const char *type,
|
network_rule(perms_t perms_p, const char *family, const char *type,
|
||||||
const char *protocol, struct cond_entry *conds);
|
const char *protocol, struct cond_entry *conds,
|
||||||
|
struct cond_entry *peer_conds);
|
||||||
network_rule(perms_t perms_p, unsigned int family, unsigned int type);
|
network_rule(perms_t perms_p, unsigned int family, unsigned int type);
|
||||||
virtual ~network_rule()
|
virtual ~network_rule()
|
||||||
{
|
{
|
||||||
|
peer.free_conds();
|
||||||
|
local.free_conds();
|
||||||
if (allow) {
|
if (allow) {
|
||||||
free(allow);
|
free(allow);
|
||||||
allow = NULL;
|
allow = NULL;
|
||||||
|
@ -138,9 +178,12 @@ public:
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
void gen_ip_conds(std::ostringstream &oss, ip_conds entry, bool is_peer, bool is_cmd);
|
||||||
bool gen_net_rule(Profile &prof, u16 family, unsigned int type_mask);
|
bool gen_net_rule(Profile &prof, u16 family, unsigned int type_mask);
|
||||||
void set_netperm(unsigned int family, unsigned int type);
|
void set_netperm(unsigned int family, unsigned int type);
|
||||||
void update_compat_net(void);
|
void update_compat_net(void);
|
||||||
|
bool parse_address(ip_conds &entry);
|
||||||
|
bool parse_port(ip_conds &entry);
|
||||||
|
|
||||||
virtual bool valid_prefix(const prefixes &p, const char *&error) {
|
virtual bool valid_prefix(const prefixes &p, const char *&error) {
|
||||||
if (p.owner) {
|
if (p.owner) {
|
||||||
|
|
|
@ -1083,24 +1083,20 @@ link_rule: TOK_LINK opt_subset_flag id_or_var TOK_ARROW id_or_var TOK_END_OF_RUL
|
||||||
$$ = entry;
|
$$ = entry;
|
||||||
};
|
};
|
||||||
|
|
||||||
network_rule: TOK_NETWORK opt_net_perm opt_cond_list TOK_END_OF_RULE
|
network_rule: TOK_NETWORK opt_net_perm opt_conds opt_cond_list TOK_END_OF_RULE
|
||||||
{
|
{
|
||||||
network_rule *entry;
|
network_rule *entry;
|
||||||
|
|
||||||
entry = new network_rule($2, $3.list);
|
if ($4.name) {
|
||||||
|
if (strcmp($4.name, "peer") != 0)
|
||||||
|
yyerror(_("network rule: invalid conditional group %s=()"), $4.name);
|
||||||
|
free($4.name);
|
||||||
|
}
|
||||||
|
entry = new network_rule($2, $3, $4.list);
|
||||||
$$ = entry;
|
$$ = entry;
|
||||||
}
|
}
|
||||||
|
|
||||||
network_rule: TOK_NETWORK opt_net_perm TOK_ID opt_cond_list TOK_END_OF_RULE
|
network_rule: TOK_NETWORK opt_net_perm TOK_ID opt_conds opt_cond_list TOK_END_OF_RULE
|
||||||
{
|
|
||||||
network_rule *entry;
|
|
||||||
|
|
||||||
entry = new network_rule($2, $3, NULL, NULL, $4.list);
|
|
||||||
free($3);
|
|
||||||
$$ = entry;
|
|
||||||
}
|
|
||||||
|
|
||||||
network_rule: TOK_NETWORK opt_net_perm TOK_ID TOK_ID opt_cond_list TOK_END_OF_RULE
|
|
||||||
{
|
{
|
||||||
network_rule *entry;
|
network_rule *entry;
|
||||||
|
|
||||||
|
@ -1109,7 +1105,21 @@ network_rule: TOK_NETWORK opt_net_perm TOK_ID TOK_ID opt_cond_list TOK_END_OF_RU
|
||||||
yyerror(_("network rule: invalid conditional group %s=()"), $5.name);
|
yyerror(_("network rule: invalid conditional group %s=()"), $5.name);
|
||||||
free($5.name);
|
free($5.name);
|
||||||
}
|
}
|
||||||
entry = new network_rule($2, $3, $4, NULL, $5.list);
|
entry = new network_rule($2, $3, NULL, NULL, $4, $5.list);
|
||||||
|
free($3);
|
||||||
|
$$ = entry;
|
||||||
|
}
|
||||||
|
|
||||||
|
network_rule: TOK_NETWORK opt_net_perm TOK_ID TOK_ID opt_conds opt_cond_list TOK_END_OF_RULE
|
||||||
|
{
|
||||||
|
network_rule *entry;
|
||||||
|
|
||||||
|
if ($6.name) {
|
||||||
|
if (strcmp($6.name, "peer") != 0)
|
||||||
|
yyerror(_("network rule: invalid conditional group %s=()"), $6.name);
|
||||||
|
free($6.name);
|
||||||
|
}
|
||||||
|
entry = new network_rule($2, $3, $4, NULL, $5, $6.list);
|
||||||
free($3);
|
free($3);
|
||||||
free($4);
|
free($4);
|
||||||
$$ = entry;
|
$$ = entry;
|
||||||
|
|
Loading…
Add table
Reference in a new issue