104 |
} |
} |
105 |
|
|
106 |
/** |
/** |
107 |
|
* ccs_parse_ip_address - Parse an IP address. |
108 |
|
* |
109 |
|
* @address: String to parse. |
110 |
|
* @min: Pointer to store min address. |
111 |
|
* @max: Pointer to store max address. |
112 |
|
* |
113 |
|
* Returns 2 if @address is an IPv6, 1 if @address is an IPv4, 0 otherwise. |
114 |
|
*/ |
115 |
|
static int ccs_parse_ip_address(char *address, u16 *min, u16 *max) |
116 |
|
{ |
117 |
|
int count = sscanf(address, "%hx:%hx:%hx:%hx:%hx:%hx:%hx:%hx" |
118 |
|
"-%hx:%hx:%hx:%hx:%hx:%hx:%hx:%hx", |
119 |
|
&min[0], &min[1], &min[2], &min[3], |
120 |
|
&min[4], &min[5], &min[6], &min[7], |
121 |
|
&max[0], &max[1], &max[2], &max[3], |
122 |
|
&max[4], &max[5], &max[6], &max[7]); |
123 |
|
if (count == 8 || count == 16) { |
124 |
|
u8 i; |
125 |
|
if (count == 8) |
126 |
|
memmove(max, min, sizeof(u16) * 8); |
127 |
|
for (i = 0; i < 8; i++) { |
128 |
|
min[i] = htons(min[i]); |
129 |
|
max[i] = htons(max[i]); |
130 |
|
} |
131 |
|
return 2; |
132 |
|
} |
133 |
|
count = sscanf(address, "%hu.%hu.%hu.%hu-%hu.%hu.%hu.%hu", |
134 |
|
&min[0], &min[1], &min[2], &min[3], |
135 |
|
&max[0], &max[1], &max[2], &max[3]); |
136 |
|
if (count == 4 || count == 8) { |
137 |
|
u32 ip = htonl((((u8) min[0]) << 24) + (((u8) min[1]) << 16) |
138 |
|
+ (((u8) min[2]) << 8) + (u8) min[3]); |
139 |
|
memmove(min, &ip, sizeof(ip)); |
140 |
|
if (count == 8) |
141 |
|
ip = htonl((((u8) max[0]) << 24) + (((u8) max[1]) << 16) |
142 |
|
+ (((u8) max[2]) << 8) + (u8) max[3]); |
143 |
|
memmove(max, &ip, sizeof(ip)); |
144 |
|
return 1; |
145 |
|
} |
146 |
|
return 0; |
147 |
|
} |
148 |
|
|
149 |
|
/** |
150 |
* ccs_update_address_group_entry - Update "struct ccs_address_group_entry" list. |
* ccs_update_address_group_entry - Update "struct ccs_address_group_entry" list. |
151 |
* |
* |
152 |
* @group_name: The name of address group. |
* @group_name: The name of address group. |
153 |
* @is_ipv6: True if @min_address and @max_address are IPv6 addresses. |
* @address: IP address. |
|
* @min_address: Start of IPv4 or IPv6 address range. |
|
|
* @max_address: End of IPv4 or IPv6 address range. |
|
154 |
* @is_delete: True if it is a delete request. |
* @is_delete: True if it is a delete request. |
155 |
* |
* |
156 |
* Returns 0 on success, negative value otherwise. |
* Returns 0 on success, negative value otherwise. |
157 |
*/ |
*/ |
158 |
static int ccs_update_address_group_entry(const char *group_name, |
static int ccs_update_address_group_entry(const char *group_name, |
159 |
const bool is_ipv6, |
char *address, const bool is_delete) |
|
const u16 *min_address, |
|
|
const u16 *max_address, |
|
|
const bool is_delete) |
|
160 |
{ |
{ |
161 |
struct ccs_address_group_entry *group; |
struct ccs_address_group_entry *group; |
162 |
struct ccs_address_group_member *entry = NULL; |
struct ccs_address_group_member *entry = NULL; |
164 |
const struct in6_addr *saved_min_address = NULL; |
const struct in6_addr *saved_min_address = NULL; |
165 |
const struct in6_addr *saved_max_address = NULL; |
const struct in6_addr *saved_max_address = NULL; |
166 |
int error = is_delete ? -ENOENT : -ENOMEM; |
int error = is_delete ? -ENOENT : -ENOMEM; |
167 |
const u32 min_ipv4_address = ntohl(*(u32 *) min_address); |
u32 min_ipv4_address = 0; |
168 |
const u32 max_ipv4_address = ntohl(*(u32 *) max_address); |
u32 max_ipv4_address = 0; |
169 |
|
u16 min_address[8]; |
170 |
|
u16 max_address[8]; |
171 |
|
bool is_ipv6 = false; |
172 |
group = ccs_get_address_group(group_name); |
group = ccs_get_address_group(group_name); |
173 |
if (!group) |
if (!group) |
174 |
return -ENOMEM; |
return -ENOMEM; |
175 |
if (is_ipv6) { |
switch (ccs_parse_ip_address(address, min_address, max_address)) { |
176 |
|
case 2: |
177 |
|
is_ipv6 = true; |
178 |
saved_min_address |
saved_min_address |
179 |
= ccs_get_ipv6_address((struct in6_addr *) |
= ccs_get_ipv6_address((struct in6_addr *) |
180 |
min_address); |
min_address); |
183 |
max_address); |
max_address); |
184 |
if (!saved_min_address || !saved_max_address) |
if (!saved_min_address || !saved_max_address) |
185 |
goto out; |
goto out; |
186 |
|
break; |
187 |
|
case 1: |
188 |
|
min_ipv4_address = ntohl(*(u32 *) min_address); |
189 |
|
max_ipv4_address = ntohl(*(u32 *) max_address); |
190 |
|
break; |
191 |
|
default: |
192 |
|
goto out; |
193 |
} |
} |
194 |
if (!is_delete) |
if (!is_delete) |
195 |
entry = kzalloc(sizeof(*entry), GFP_KERNEL); |
entry = kzalloc(sizeof(*entry), GFP_KERNEL); |
236 |
} |
} |
237 |
|
|
238 |
/** |
/** |
|
* ccs_parse_ip_address - Parse an IP address. |
|
|
* |
|
|
* @address: String to parse. |
|
|
* @min: Pointer to store min address. |
|
|
* @max: Pointer to store max address. |
|
|
* |
|
|
* Returns 2 if @address is an IPv6, 1 if @address is an IPv4, 0 otherwise. |
|
|
*/ |
|
|
static int ccs_parse_ip_address(char *address, u16 *min, u16 *max) |
|
|
{ |
|
|
int count = sscanf(address, "%hx:%hx:%hx:%hx:%hx:%hx:%hx:%hx" |
|
|
"-%hx:%hx:%hx:%hx:%hx:%hx:%hx:%hx", |
|
|
&min[0], &min[1], &min[2], &min[3], |
|
|
&min[4], &min[5], &min[6], &min[7], |
|
|
&max[0], &max[1], &max[2], &max[3], |
|
|
&max[4], &max[5], &max[6], &max[7]); |
|
|
if (count == 8 || count == 16) { |
|
|
u8 i; |
|
|
if (count == 8) |
|
|
memmove(max, min, sizeof(u16) * 8); |
|
|
for (i = 0; i < 8; i++) { |
|
|
min[i] = htons(min[i]); |
|
|
max[i] = htons(max[i]); |
|
|
} |
|
|
return 2; |
|
|
} |
|
|
count = sscanf(address, "%hu.%hu.%hu.%hu-%hu.%hu.%hu.%hu", |
|
|
&min[0], &min[1], &min[2], &min[3], |
|
|
&max[0], &max[1], &max[2], &max[3]); |
|
|
if (count == 4 || count == 8) { |
|
|
u32 ip = htonl((((u8) min[0]) << 24) + (((u8) min[1]) << 16) |
|
|
+ (((u8) min[2]) << 8) + (u8) min[3]); |
|
|
memmove(min, &ip, sizeof(ip)); |
|
|
if (count == 8) |
|
|
ip = htonl((((u8) max[0]) << 24) + (((u8) max[1]) << 16) |
|
|
+ (((u8) max[2]) << 8) + (u8) max[3]); |
|
|
memmove(max, &ip, sizeof(ip)); |
|
|
return 1; |
|
|
} |
|
|
return 0; |
|
|
} |
|
|
|
|
|
/** |
|
239 |
* ccs_write_address_group_policy - Write "struct ccs_address_group_entry" list. |
* ccs_write_address_group_policy - Write "struct ccs_address_group_entry" list. |
240 |
* |
* |
241 |
* @data: String to parse. |
* @data: String to parse. |
246 |
int ccs_write_address_group_policy(char *data, const bool is_delete) |
int ccs_write_address_group_policy(char *data, const bool is_delete) |
247 |
{ |
{ |
248 |
char *w[2]; |
char *w[2]; |
|
bool is_ipv6; |
|
|
u16 min_address[8]; |
|
|
u16 max_address[8]; |
|
249 |
if (!ccs_tokenize(data, w, sizeof(w)) || !w[1][0]) |
if (!ccs_tokenize(data, w, sizeof(w)) || !w[1][0]) |
250 |
return -EINVAL; |
return -EINVAL; |
251 |
switch (ccs_parse_ip_address(w[1], min_address, max_address)) { |
return ccs_update_address_group_entry(w[0], w[1], is_delete); |
|
case 2: |
|
|
is_ipv6 = true; |
|
|
break; |
|
|
case 1: |
|
|
is_ipv6 = false; |
|
|
break; |
|
|
default: |
|
|
return -EINVAL; |
|
|
} |
|
|
return ccs_update_address_group_entry(w[0], is_ipv6, min_address, |
|
|
max_address, is_delete); |
|
252 |
} |
} |
253 |
|
|
254 |
/** |
/** |
425 |
/** |
/** |
426 |
* ccs_update_network_entry - Update "struct ccs_ip_network_acl_record" list. |
* ccs_update_network_entry - Update "struct ccs_ip_network_acl_record" list. |
427 |
* |
* |
428 |
|
* @protocol: Protocol name. |
429 |
* @operation: Type of operation. |
* @operation: Type of operation. |
430 |
* @record_type: Type of address. |
* @address: Address. |
431 |
* @group: Name of group. May be NULL. |
* @port: Port number. |
|
* @min_address: Start of IPv4 or IPv6 address range. |
|
|
* @max_address: End of IPv4 or IPv6 address range. |
|
|
* @min_port: Start of port number range. |
|
|
* @max_port: End of port number range. |
|
432 |
* @domain: Pointer to "struct ccs_domain_info". |
* @domain: Pointer to "struct ccs_domain_info". |
433 |
* @condition: Pointer to "struct ccs_condition". May be NULL. |
* @condition: Pointer to "struct ccs_condition". May be NULL. |
434 |
* @is_delete: True if it is a delete request. |
* @is_delete: True if it is a delete request. |
435 |
* |
* |
436 |
* Returns 0 on success, negative value otherwise. |
* Returns 0 on success, negative value otherwise. |
437 |
*/ |
*/ |
438 |
static int ccs_update_network_entry(const u8 operation, const u8 record_type, |
static int ccs_update_network_entry(const char *protocol, |
439 |
const char *address_group_name, |
const char *operation, char *address, |
440 |
const char *port_group_name, |
char *port, struct ccs_domain_info *domain, |
|
const u32 *min_address, |
|
|
const u32 *max_address, |
|
|
const u16 min_port, const u16 max_port, |
|
|
struct ccs_domain_info *domain, |
|
441 |
struct ccs_condition *condition, |
struct ccs_condition *condition, |
442 |
const bool is_delete) |
const bool is_delete) |
443 |
{ |
{ |
446 |
struct ccs_acl_info *ptr; |
struct ccs_acl_info *ptr; |
447 |
struct ccs_ip_network_acl_record e; |
struct ccs_ip_network_acl_record e; |
448 |
struct ccs_ip_network_acl_record *entry = NULL; |
struct ccs_ip_network_acl_record *entry = NULL; |
449 |
|
u16 min_address[8]; |
450 |
|
u16 max_address[8]; |
451 |
int error = is_delete ? -ENOENT : -ENOMEM; |
int error = is_delete ? -ENOENT : -ENOMEM; |
452 |
|
u8 sock_type; |
453 |
memset(&e, 0, sizeof(e)); |
memset(&e, 0, sizeof(e)); |
454 |
e.head.type = TYPE_IP_NETWORK_ACL; |
e.head.type = TYPE_IP_NETWORK_ACL; |
455 |
e.head.cond = condition; |
e.head.cond = condition; |
|
e.operation_type = operation; |
|
|
e.record_type = record_type; |
|
456 |
if (!domain) |
if (!domain) |
457 |
return -EINVAL; |
return -EINVAL; |
458 |
if (address_group_name) { |
if (!strcmp(protocol, "TCP")) |
459 |
e.address.group = ccs_get_address_group(address_group_name); |
sock_type = SOCK_STREAM; |
460 |
if (!e.address.group) |
else if (!strcmp(protocol, "UDP")) |
461 |
return -ENOMEM; |
sock_type = SOCK_DGRAM; |
462 |
} else if (record_type == IP_RECORD_TYPE_IPv6) { |
else if (!strcmp(protocol, "RAW")) |
463 |
|
sock_type = SOCK_RAW; |
464 |
|
else |
465 |
|
return -EINVAL; |
466 |
|
if (!strcmp(operation, "bind")) |
467 |
|
switch (sock_type) { |
468 |
|
case SOCK_STREAM: |
469 |
|
e.operation_type = NETWORK_ACL_TCP_BIND; |
470 |
|
break; |
471 |
|
case SOCK_DGRAM: |
472 |
|
e.operation_type = NETWORK_ACL_UDP_BIND; |
473 |
|
break; |
474 |
|
default: |
475 |
|
e.operation_type = NETWORK_ACL_RAW_BIND; |
476 |
|
break; |
477 |
|
} |
478 |
|
else if (!strcmp(operation, "connect")) |
479 |
|
switch (sock_type) { |
480 |
|
case SOCK_STREAM: |
481 |
|
e.operation_type = NETWORK_ACL_TCP_CONNECT; |
482 |
|
break; |
483 |
|
case SOCK_DGRAM: |
484 |
|
e.operation_type = NETWORK_ACL_UDP_CONNECT; |
485 |
|
break; |
486 |
|
default: |
487 |
|
e.operation_type = NETWORK_ACL_RAW_CONNECT; |
488 |
|
break; |
489 |
|
} |
490 |
|
else if (sock_type == SOCK_STREAM && !strcmp(operation, "listen")) |
491 |
|
e.operation_type = NETWORK_ACL_TCP_LISTEN; |
492 |
|
else if (sock_type == SOCK_STREAM && !strcmp(operation, "accept")) |
493 |
|
e.operation_type = NETWORK_ACL_TCP_ACCEPT; |
494 |
|
else |
495 |
|
return -EINVAL; |
496 |
|
switch (ccs_parse_ip_address(address, min_address, max_address)) { |
497 |
|
case 2: |
498 |
|
e.record_type = IP_RECORD_TYPE_IPv6; |
499 |
e.address.ipv6.min = ccs_get_ipv6_address((struct in6_addr *) |
e.address.ipv6.min = ccs_get_ipv6_address((struct in6_addr *) |
500 |
min_address); |
min_address); |
501 |
e.address.ipv6.max = ccs_get_ipv6_address((struct in6_addr *) |
e.address.ipv6.max = ccs_get_ipv6_address((struct in6_addr *) |
502 |
max_address); |
max_address); |
503 |
if (!e.address.ipv6.min || !e.address.ipv6.max) |
if (!e.address.ipv6.min || !e.address.ipv6.max) |
504 |
goto out; |
goto out; |
505 |
} else { |
break; |
506 |
/* use host byte order to allow u32 comparison than memcmp().*/ |
case 1: |
507 |
e.address.ipv4.min = ntohl(*min_address); |
e.record_type = IP_RECORD_TYPE_IPv4; |
508 |
e.address.ipv4.max = ntohl(*max_address); |
/* use host byte order to allow u32 comparison.*/ |
509 |
} |
e.address.ipv4.min = ntohl(* (u32 *) min_address); |
510 |
if (port_group_name) { |
e.address.ipv4.max = ntohl(* (u32 *) max_address); |
511 |
if (!ccs_check_and_save_number(port_group_name, &e.port)) |
break; |
512 |
goto out; |
default: |
513 |
} else { |
if (address[0] != '@') |
514 |
e.port.values[0] = min_port; |
return -EINVAL; |
515 |
e.port.values[1] = max_port; |
e.record_type = IP_RECORD_TYPE_ADDRESS_GROUP; |
516 |
|
e.address.group = ccs_get_address_group(address + 1); |
517 |
|
if (!e.address.group) |
518 |
|
return -ENOMEM; |
519 |
|
break; |
520 |
} |
} |
521 |
|
if (!ccs_parse_number_union(port, &e.port)) |
522 |
|
goto out; |
523 |
if (is_delete) |
if (is_delete) |
524 |
goto delete; |
goto delete; |
525 |
entry = kzalloc(sizeof(*entry), GFP_KERNEL); |
entry = kzalloc(sizeof(*entry), GFP_KERNEL); |
562 |
} |
} |
563 |
mutex_unlock(&ccs_policy_lock); |
mutex_unlock(&ccs_policy_lock); |
564 |
out: |
out: |
565 |
if (address_group_name) |
if (address[0] == '@') |
566 |
ccs_put_address_group(e.address.group); |
ccs_put_address_group(e.address.group); |
567 |
else if (record_type == IP_RECORD_TYPE_IPv6) { |
else if (e.record_type == IP_RECORD_TYPE_IPv6) { |
568 |
ccs_put_ipv6_address(e.address.ipv6.min); |
ccs_put_ipv6_address(e.address.ipv6.min); |
569 |
ccs_put_ipv6_address(e.address.ipv6.max); |
ccs_put_ipv6_address(e.address.ipv6.max); |
570 |
} |
} |
571 |
if (port_group_name) |
ccs_put_number_union(&e.port); |
|
ccs_put_number_group(e.port.group); |
|
572 |
kfree(entry); |
kfree(entry); |
573 |
return error; |
return error; |
574 |
} |
} |
650 |
goto retry; |
goto retry; |
651 |
return err; |
return err; |
652 |
} else if (ccs_domain_quota_ok(&r)) { |
} else if (ccs_domain_quota_ok(&r)) { |
653 |
struct ccs_condition *cond = ccs_handler_cond(); |
char *tmp = kmalloc(PAGE_SIZE, GFP_KERNEL); |
654 |
ccs_update_network_entry(operation, is_ipv6 ? |
if (tmp) { |
655 |
IP_RECORD_TYPE_IPv6 : |
struct ccs_condition *cond = ccs_handler_cond(); |
656 |
IP_RECORD_TYPE_IPv4, |
snprintf(tmp, PAGE_SIZE - 1, "%s %s %u", keyword, buf, |
657 |
NULL, NULL, address, address, port, |
port); |
658 |
port, r.domain, cond, false); |
ccs_write_network_policy(tmp, r.domain, cond, false); |
659 |
ccs_put_condition(cond); |
ccs_put_condition(cond); |
660 |
|
kfree(tmp); |
661 |
|
} |
662 |
} |
} |
663 |
return 0; |
return 0; |
664 |
} |
} |
698 |
const bool is_delete) |
const bool is_delete) |
699 |
{ |
{ |
700 |
char *w[4]; |
char *w[4]; |
|
u8 sock_type; |
|
|
u8 operation; |
|
|
u8 record_type; |
|
|
u16 min_address[8]; |
|
|
u16 max_address[8]; |
|
|
const char *address_group_name = NULL; |
|
|
const char *port_group_name = NULL; |
|
|
u16 min_port; |
|
|
u16 max_port; |
|
701 |
if (!ccs_tokenize(data, w, sizeof(w)) || !w[3][0]) |
if (!ccs_tokenize(data, w, sizeof(w)) || !w[3][0]) |
702 |
return -EINVAL; |
return -EINVAL; |
703 |
if (!strcmp(w[0], "TCP")) |
return ccs_update_network_entry(w[0], w[1], w[2], w[3], domain, |
704 |
sock_type = SOCK_STREAM; |
condition, is_delete); |
|
else if (!strcmp(w[0], "UDP")) |
|
|
sock_type = SOCK_DGRAM; |
|
|
else if (!strcmp(w[0], "RAW")) |
|
|
sock_type = SOCK_RAW; |
|
|
else |
|
|
goto out; |
|
|
if (!strcmp(w[1], "bind")) |
|
|
switch (sock_type) { |
|
|
case SOCK_STREAM: |
|
|
operation = NETWORK_ACL_TCP_BIND; |
|
|
break; |
|
|
case SOCK_DGRAM: |
|
|
operation = NETWORK_ACL_UDP_BIND; |
|
|
break; |
|
|
default: |
|
|
operation = NETWORK_ACL_RAW_BIND; |
|
|
} |
|
|
else if (!strcmp(w[1], "connect")) |
|
|
switch (sock_type) { |
|
|
case SOCK_STREAM: |
|
|
operation = NETWORK_ACL_TCP_CONNECT; |
|
|
break; |
|
|
case SOCK_DGRAM: |
|
|
operation = NETWORK_ACL_UDP_CONNECT; |
|
|
break; |
|
|
default: |
|
|
operation = NETWORK_ACL_RAW_CONNECT; |
|
|
} |
|
|
else if (sock_type == SOCK_STREAM && !strcmp(w[1], "listen")) |
|
|
operation = NETWORK_ACL_TCP_LISTEN; |
|
|
else if (sock_type == SOCK_STREAM && !strcmp(w[1], "accept")) |
|
|
operation = NETWORK_ACL_TCP_ACCEPT; |
|
|
else |
|
|
goto out; |
|
|
switch (ccs_parse_ip_address(w[2], min_address, max_address)) { |
|
|
case 2: |
|
|
record_type = IP_RECORD_TYPE_IPv6; |
|
|
break; |
|
|
case 1: |
|
|
record_type = IP_RECORD_TYPE_IPv4; |
|
|
break; |
|
|
default: |
|
|
if (w[2][0] != '@') |
|
|
goto out; |
|
|
address_group_name = w[2] + 1; |
|
|
record_type = IP_RECORD_TYPE_ADDRESS_GROUP; |
|
|
break; |
|
|
} |
|
|
switch (sscanf(w[3], "%hu-%hu", &min_port, &max_port)) { |
|
|
case 2: |
|
|
break; |
|
|
case 1: |
|
|
max_port = min_port; |
|
|
break; |
|
|
default: |
|
|
if (w[3][0] != '@') |
|
|
goto out; |
|
|
port_group_name = w[3]; |
|
|
break; |
|
|
} |
|
|
return ccs_update_network_entry(operation, record_type, |
|
|
address_group_name, port_group_name, |
|
|
(u32 *) min_address, |
|
|
(u32 *) max_address, |
|
|
min_port, max_port, domain, condition, |
|
|
is_delete); |
|
|
out: |
|
|
return -EINVAL; |
|
705 |
} |
} |
706 |
|
|
707 |
/** |
/** |