aboutsummaryrefslogtreecommitdiff
path: root/src/sg.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/sg.c')
-rw-r--r--src/sg.c129
1 files changed, 121 insertions, 8 deletions
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.