aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSergey Poznyakoff <gray@gnu.org.ua>2013-12-16 14:58:32 +0200
committerSergey Poznyakoff <gray@gnu.org.ua>2013-12-16 14:58:32 +0200
commit7641c3ffc301d1b4fd444d39e18ca85e1a86fba8 (patch)
tree93ef45435174a91a91d01ba9167e36f3a31c0177
parent29c02b8a1b9b3b262d1e383f6cd211275f24f622 (diff)
downloadeclat-7641c3ffc301d1b4fd444d39e18ca85e1a86fba8.tar.gz
eclat-7641c3ffc301d1b4fd444d39e18ca85e1a86fba8.tar.bz2
Improve sg.
Accept --list without argument (list all groups). Accept host and service names as arguments to the --source and --port options. * src/sg-cl.opt (parse_options): Accept --list without argument. * src/sg.c (add_source_cidr, str2port): New functions. (flush_rule): Use the above to process source CIDRs and port numbers.
-rw-r--r--src/sg-cl.opt21
-rw-r--r--src/sg.c129
2 files changed, 133 insertions, 17 deletions
diff --git a/src/sg-cl.opt b/src/sg-cl.opt
index 265aa4b..45c5bf4 100644
--- a/src/sg-cl.opt
+++ b/src/sg-cl.opt
@@ -15,7 +15,7 @@
along with Eclat. If not, see <http://www.gnu.org/licenses/>. */
ECLAT_CL_BEGIN([<modify ingress rules of a security group>],
- [<GROUPARG>])
+ [<[GROUPID-OR-NAME]>])
OPTION(add,A,,
[<add rules>])
@@ -114,17 +114,20 @@ ECLAT_CL_PARSER(parse_options, [<int argc, char *argv[]>],[<
int idx;
GETOPT(argc, argv, idx, exit(EX_USAGE))
- if (!command)
- die(EX_USAGE, "either --list or --add or --delete must be given");
- if (list_option &&
- (rule_n > 1 || group_list || source_list || from_port || to_port))
- die(EX_USAGE, "conflicting options");
-
argc -= idx;
argv += idx;
- if (argc != 1)
+
+ if (!command)
+ die(EX_USAGE, "either --list or --add or --delete must be given");
+ if (list_option) {
+ if (rule_n > 1 || group_list || source_list ||
+ from_port || to_port)
+ die(EX_USAGE, "conflicting options");
+ if (argc > 1)
+ die(EX_USAGE, "bad number of arguments");
+ } else if (argc != 1)
die(EX_USAGE, "bad number of arguments");
- translate_ids(1, argv, rt[dest_n].map);
+ translate_ids(argc, argv, rt[dest_n].map);
eclat_query_add_param(env->query, "Action", command);
if (list_option)
diff --git a/src/sg.c b/src/sg.c
index 098477e..094798e 100644
--- a/src/sg.c
+++ b/src/sg.c
@@ -15,6 +15,8 @@
along with Eclat. If not, see <http://www.gnu.org/licenses/>. */
#include "eclat.h"
+#include <arpa/inet.h>
+#include <netdb.h>
#define GROUP_ID 0
#define GROUP_NAME 1
@@ -48,6 +50,113 @@ static char *from_port, *to_port;
static char *bufptr = NULL;
static size_t bufsize = 0;
+static int
+add_source_cidr(char *str, int i)
+{
+ char *p;
+ struct in_addr addr;
+ unsigned long n;
+ char masklen[3];
+ char cidrbuf[19];
+ struct addrinfo hints, *res, *ap;
+ struct protoent *pe;
+
+ p = strchr(str, '/');
+ if (p) {
+ char *q;
+
+ *p++ = 0;
+ n = strtoul(p, &q, 10);
+ if (*q == 0) {
+ if (n <= 0 || n > 32) {
+ p[-1] = '/';
+ die(EX_USAGE, "invalid network mask in %s",
+ str);
+ }
+ strcpy(masklen, p);
+ } else {
+ int j;
+
+ if (inet_aton(p, &addr) == 0) {
+ p[-1] = '/';
+ die(EX_USAGE, "invalid network mask in %s",
+ str);
+ }
+ n = addr.s_addr;
+ for (j = 0; j < 32 && (n & 1); j++, n >>= 1)
+ ;
+ if (n) {
+ p[-1] = '/';
+ die(EX_USAGE, "invalid network mask in %s",
+ str);
+ }
+ masklen[0] = j/10 + '0';
+ masklen[1] = j%10 + '0';
+ masklen[2] = 0;
+ }
+ } else
+ strcpy(masklen, "32");
+
+ memset(&hints, 0, sizeof(hints));
+ pe = getprotobyname(proto);
+ if (pe)
+ hints.ai_protocol = pe->p_proto;
+ else {
+ errno = 0;
+ n = strtoul(proto, &p, 0);
+ if (errno || *p)
+ die(EX_USAGE, "%s: unrecognized protocol");
+ hints.ai_protocol = n;
+ }
+ hints.ai_family = AF_INET;
+
+ if (getaddrinfo(str, NULL, &hints, &res)) {
+ p[-1] = '/';
+ die(EX_USAGE, "invalid network address in %s", str);
+ }
+
+ for (ap = res; ap; ap = ap->ai_next) {
+ struct sockaddr_in *sp = (struct sockaddr_in *) ap->ai_addr;
+ char *s = inet_ntoa(sp->sin_addr);
+ if (s) {
+ snprintf(cidrbuf, sizeof cidrbuf,
+ "%s/%s", s, masklen);
+ grecs_asprintf(&bufptr, &bufsize,
+ "IpPermissions.%d.IpRanges.%d.CidrIp",
+ rule_n, i);
+ eclat_query_add_param(query, bufptr, cidrbuf);
+ i++;
+ }
+ }
+ freeaddrinfo(res);
+
+ return i;
+}
+
+static char *
+str2port(const char *str, char **pbuf, size_t *psize)
+{
+ unsigned long n;
+ struct servent *p;
+ char *end;
+
+ p = getservbyname(str, proto);
+ if (p) {
+ grecs_asprintf(pbuf, psize, "%d", (int) ntohs(p->s_port));
+ return *pbuf;
+ }
+
+ errno = 0;
+ n = strtoul(str, &end, 10);
+ if (errno)
+ die(EX_USAGE, "%s: invalid port: %s", str, strerror(errno));
+ if (*end)
+ die(EX_USAGE, "%s: invalid port", str);
+ if (n == 0 || n > USHRT_MAX)
+ die(EX_USAGE, "%s: port number out of range", str);
+ return (char *) str;
+}
+
static void
flush_rule()
{
@@ -77,12 +186,10 @@ flush_rule()
grecs_list_clear(group_list);
}
if (source_list) {
- for (i = 1, ep = source_list->head; ep; ep = ep->next, i++) {
- grecs_asprintf(&bufptr, &bufsize,
- "IpPermissions.%d.IpRanges.%d.CidrIp",
- rule_n, i);
- eclat_query_add_param(query, bufptr, (char*) ep->data);
- }
+ int j = 1;
+
+ for (i = 1, ep = source_list->head; ep; ep = ep->next, i++)
+ j = add_source_cidr((char*) ep->data, j);
grecs_list_clear(source_list);
} else if (!group_list) {
grecs_asprintf(&bufptr, &bufsize,
@@ -92,12 +199,18 @@ flush_rule()
}
if (from_port) {
+ char *pbuf = NULL;
+ size_t psize = 0;
+
grecs_asprintf(&bufptr, &bufsize, "IpPermissions.%d.FromPort",
rule_n);
- eclat_query_add_param(query, bufptr, from_port);
+ eclat_query_add_param(query, bufptr,
+ str2port(from_port, &pbuf, &psize));
grecs_asprintf(&bufptr, &bufsize, "IpPermissions.%d.ToPort",
rule_n);
- eclat_query_add_param(query, bufptr, to_port);
+ eclat_query_add_param(query, bufptr,
+ str2port(to_port, &pbuf, &psize));
+ free(pbuf);
}
from_port = to_port = NULL;
++rule_n;

Return to:

Send suggestions and report system problems to the System administrator.