summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--domain2name.c99
-rw-r--r--domain2name_test.c9
-rw-r--r--main.c156
3 files changed, 216 insertions, 48 deletions
diff --git a/domain2name.c b/domain2name.c
index 46fd2a3..7c84fbb 100644
--- a/domain2name.c
+++ b/domain2name.c
@@ -1,8 +1,8 @@
-int domain2name_len (const char * s, int l) {
- int r = 1; /* ending terminator */
- int o = 0; /* label offset */
- for (int i = 0; i < l; i++) {
- if (s[i] == '.') {
+int domain2name_len (const char * s, int l) { /* TODO make domain2name FAIL at empty label (..) */
+ int r = 1; /* ending terminator */ /* make functions FAIL at label.length > 63 */
+ int o = 0; /* label offset */ /* currently domain2name never fails */
+ for (int i = 0; i < l; i++) { /* NOTE when using BOTH _len, check that they are */
+ if (s[i] == '.') { /* NOT negative. d2n_len will fail in d future */
if (!o) /* double period or starting period, label is empty */
break;
o = 0;
@@ -15,9 +15,9 @@ int domain2name_len (const char * s, int l) {
}
return r;
}
-int domain2name (char * d, const char * s, int l) { /* l is length of s */
- char * c = d; /* where to write the label size when done with label */
- char * w = d;
+int domain2name (char * n /* at least _len bytes */, const char * s, int l) { /* l is length of s */
+ char * c = n; /* where to write the label size when done with label */
+ char * w = n;
int o = 0; /* label offset */
for (int i = 0; i <= l /* yes, we go one more ... */; i++) {
if (i == l /* ... here */ || s[i] == '.') { /* end of label or end of last label */
@@ -36,5 +36,84 @@ int domain2name (char * d, const char * s, int l) { /* l is length of s */
*c = 63; /* it at 63 bytes */
}
*w++ = '\0'; /* luckily this makes domain2name kind of safe for handling as a string (: */
- return w-d; /* we return number of bytes written */
-} /* d must be allocated for at least _len. */
+ return w-n; /* we return number of bytes written */
+} /* no compression, it's 2022, net bandwidth is unlimited. n2d OFC does decompress ptrs acc2 std. */
+int name2domain_len (const char * u /* >= 512 bytes */, const char * n /* name */) {
+#define N2DO(x) ((x) & ~(1 << 7 & 1 << 6)) /* pointer offset */
+ int r = 0;
+ if (n < u+512 && *n == '\0') {
+ return 2;
+ }
+ while (n < u+512) {
+ if (*n & 1 << 7) {
+ if (!(*n & 1 << 6))
+ return -1; /* 10xx xxxx not implemented - reserved for future use */
+ n = u + N2DO(*n);
+ continue;
+ }
+ if (*n & 1 << 6)
+ return -2; /* 01xx xxxx not implemented - reserved for future use */
+ if (!*n)
+ return r+1;
+ r += *n+1;
+ n += *n+1;
+ }
+ return -3; /* malformed packet */
+} /* returns number of bytes needed for buffer, passed as the first argument of name2domain(). */
+const char * name2domain (char * d /* >= _len B */, const char * u /* >= 512 B */, const char * n) {
+ char * w = d; /* if d is NULL nothing is written and last byte of name is returned */
+ const char * r = NULL;
+ if (n < u+512 && *n == '\0') {
+ *w++ = '.';
+ *w++ = '\0';
+ return n;
+ }
+ while (n < u+512) {
+ if (*n & 1 << 7) {
+ if (!(*n & 1 << 6))
+ return NULL; /* 10xx xxxx N/I - reserved for future use as per RFC */
+ n = u + N2DO(*n);
+ r = n;
+ continue;
+ }
+ if (*n & 1 << 6)
+ return NULL; /* 01xx xxxx N/I - reserved for future use as per RFC */
+ if (!*n) { /* end of name */
+ if (w)
+ *w++ = '\0';
+ return r ? r : n;
+ }
+ const char * x = n+*n;
+ n++;
+ if (!(x < u+512))
+ return NULL; /* malformed packet */
+ while (n <= x)
+ if (w)
+ *w++ = *n++;
+ else
+ n++;
+ if (w)
+ *w++ = '.';
+ }
+ return NULL; /* malformed packet */
+} /* Returns ptr to last byte of name - '\0' or dnsptr. Ret. NULL on fail (_len also returned < 0) */
+int normalizedomain_len (const char * s, int l) {
+ int ž = domain2name_len(s, l);
+ if (ž < 0)
+ return -4;
+ char * b = alloca(ž);
+ if (domain2name(b, s, l) != ž)
+ return -5;
+ return name2domain_len(b, b);
+}
+int normalizedomain (char * d /* at least _len bytes */, const char * s, int l) {
+ int ž = domain2name_len(s, l);
+ if (ž < 0)
+ return -4;
+ char * b = alloca(ž);
+ if (domain2name(b, s, l) != ž)
+ return -5;
+ if (!name2domain(d, b, b))
+ return -6;
+ return 0;
+}
diff --git a/domain2name_test.c b/domain2name_test.c
index f0a6898..c88aa0a 100644
--- a/domain2name_test.c
+++ b/domain2name_test.c
@@ -10,6 +10,15 @@ int main (int argc, char * const argv[]) {
int r, s = domain2name_len(argv[1], strlen(argv[1]));
char * b = alloca(s);
r = domain2name(b, argv[1], strlen(argv[1]));
+ fprintf(stderr, "strlen %d name2domain_len %d\n", strlen(argv[1]), name2domain_len(b, b));
+ int l = name2domain_len(b, b);
+ if (l < 0) {
+ fprintf(stderr, "name2domain_len error: %d\n", l);
+ } else {
+ char * d = alloca(l);
+ name2domain(d, b, b);
+ fprintf(stderr, "name2domain: %s\n", d);
+ }
printf("%4dB %4dB (-:\n", s, r); /* xxd has 16 bytes per row */
printf("%s", b);
fflush(stdout);
diff --git a/main.c b/main.c
index fd77759..58fe58e 100644
--- a/main.c
+++ b/main.c
@@ -90,7 +90,7 @@ GLOBAL HEADER: 24 bytes
LINKTYP 28 bits: pkt type //tcpdump.org/linktypes.html 101 IPv4/v6 1 ether | |
PACKET HEADER: 16 bytes
SECONDS 32 bits: UNIX timestamp
- NANOSEC 32 bits: nanoseconds elapsed since the second, can also be microseconds - see MAGIC
+ SUBSECS 32 bits: nanoseconds elapsed since the second, can also be microseconds - see MAGIC
CAPTURE 32 bits: number of bytes captured from the packet following the header
ORIGLEN 32 bits: number of bytes of the original packet size (can be more than CAPTURE)
*/
@@ -115,10 +115,10 @@ HEADER:
Option byte zero denotes an end of options, NOOP is option number 1
PADDING variable: zero bytes ensuring header is aligned into 32 bit words
*/
-/* UDP PACKET: HEADER DATA https://www.ietf.org/rfc/rfc768.txt
+/* UDP PACKET: HEADER (8 bytes) DATA https://www.ietf.org/rfc/rfc768.txt
SRCPORT 16 bits
DSTPORT 16 bits
- LENGTH 16 bits: size of packet including header in bytes
+ LENGTH 16 bits: size of packet including header in bytes+8
CHCKSUM 16 bits: same algo as IP, data: pseudoheader (srcip dstip 0x0011 LENGTH) header data
*/
#define MICROSECOND 0xA1B2C3D4
@@ -141,8 +141,8 @@ struct pcap_packet {
uint32_t capture_length __attribute__((packed));
uint32_t original_length __attribute__((packed));
} __attribute__((packed));
-#define LOW_DELAY (1 << 0)
-#define HIGH_THROUGHPUT (1 << 1)
+#define LOW_DELAY (1 << 4)
+#define HIGH_THROUGHPUT (1 << 3)
#define HIGH_RELIABILITY (1 << 2)
#define ROUTINE (0 << 5)
#define PRIORITY (1 << 5)
@@ -153,9 +153,9 @@ struct pcap_packet {
#define INETCTRL (FLASH_OVERRIDE | IMMEDIATE)
#define NETCTRL (FLASH_OVERRIDE | FLASH)
#define HEADLENOR (1 << 6) /* always bitwiseOR the headlen with this to apply the version number */
-#define EVIL (1 << 13)
+#define EVIL (1 << 15)
#define DF (1 << 14)
-#define MF (1 << 15)
+#define MF (1 << 13)
#define ICMP 1
#define TCP 6
#define UDP 17
@@ -164,7 +164,7 @@ struct ip {
uint8_t srvtype; /* OR here: LOW_DELAY, HIGH_THROUGHPUT, HIGH_RELIABILITY, ROUTINE, ... */
uint16_t length __attribute__((packed)); /* header + data in 8 bit words */
uint16_t identifier __attribute__((packed));
- uint8_t foffset; /* fragment offset in 64 bit words. also or here any flags: EVIL, DF, MF */
+ uint16_t foffset /* 64b wrds */ __attribute__((packed)); /* or any flags: EVIL, DF, MF */
uint8_t ttl; /* ignored for uint8_t */
uint8_t protocol; /* ignored for uint8_t */
uint16_t checksum; /* ignoref for uint8_t */
@@ -196,20 +196,20 @@ enum class {
He,
Any = 255
};
-#define RESPONSE (1 << 0) /* :FLAGS */
-#define QUESTION (0 << 0)
-#define QUERY (1 << 1) /* must be set, even with response, this shows that it's normal query type */
-#define IQUERY (1 << 2)
-#define STATUS (QUERY | IQUERY)
-#define AA (1 << 5)
-#define TC (1 << 6)
-#define RD (1 << 7)
-#define RA (1 << 8)
-#define SUCCESS (1 << 12)
-#define FORMAT_ERROR (1 << 13)
-#define SERVFAIL (SUCCESS | FORMAT_ERROR)
-#define NXDOMAIN (1 << 14)
-#define NI (NXDOMAIN | SUCCESS)
+#define RESPONSE (1 << 15) /* :FLAGS */
+#define QUESTION (0 << 15)
+#define QUERY (0 << 11)
+#define IQUERY (1 << 11)
+#define STATUS (1 << 12)
+#define AA (1 << 10)
+#define TC (1 << 9)
+#define RD (1 << 8)
+#define RA (1 << 7)
+#define SUCCESS (0 << 0)
+#define FORMAT_ERROR (1 << 0)
+#define SERVFAIL (1 << 1)
+#define NXDOMAIN (FORMAT_ERROR | SERVFAIL)
+#define NI (1 << 2)
#define FORBIDDEN (NXDOMAIN | FORMAT_ERROR)
struct header {
uint16_t xid __attribute__((packed));
@@ -231,13 +231,13 @@ int logudp (int o /* fd */, struct sockaddr_in s, struct sockaddr_in d, char * u
struct pcap_packet p = {
.seconds = t.tv_sec,
.subseconds = t.tv_nsec,
- .capture_length = l,
- .original_length = l
+ .capture_length = sizeof(struct ip) + l + 4*2,
+ .original_length = sizeof(struct ip) + l + 4*2
};
struct ip i = {
.headlen = 5 | HEADLENOR,
.srvtype = ROUTINE,
- .length = htons(8+l),
+ .length = htons(8+l+sizeof i),
.identifier = 0x6969,
.foffset = 0,
.ttl = 69,
@@ -249,7 +249,7 @@ int logudp (int o /* fd */, struct sockaddr_in s, struct sockaddr_in d, char * u
#define LOGUDP_L (sizeof p + sizeof i + 4*2 + l)
char * c, * b = alloca(LOGUDP_L); /* to do in one write (thread safe) */
char * n = "\0"; /* as per udp rfc when no checksum was calculated (-: */
- uint16_t v = htons(l);
+ uint16_t v = htons(l+8);
c = (char *) memcpy(b, &p, sizeof p) + sizeof p;
c = (char *) memcpy(c, &i, sizeof i) + sizeof i;
c = (char *) memcpy(c, &s.sin_port, 2) + 2;
@@ -263,6 +263,53 @@ int logudp (int o /* fd */, struct sockaddr_in s, struct sockaddr_in d, char * u
}
return LOGUDP_L;
}
+struct in_addr parse_a (const char * u /* >=512B */, const char * d, int l, int n) {
+ struct in_addr r = { /* this uses heap and does not fix heap if realloc failed. */
+ .s_addr = 0 /* returns 0.0.0.0 in case of error or if no more results for n. */
+ };
+ int y = normalizedomain_len(d, l);
+ if (y < 0)
+ return r;
+ char * ž = alloca(y);
+ if (normalizedomain(ž, d, l) < 0)
+ return r;
+ int š = ntohs(((const struct header *) u)->ancount);
+ char * o = NULL;
+ const char * c = u+sizeof(struct header);
+ while (š--) { /* there's got to be a cleaner way of */
+ int č = name2domain_len(u, c); /* doing this ... someone please review */
+ if (č < 0) /* all those functions and PLEASE run */
+ goto r; /* this program AS UNPRIVILEDGED AS */
+ if (!(o = realloc(o, č))) /* POSSIBLE! */
+ goto r;
+ if (!(c = name2domain(o, u, c)))
+ goto r;
+ if (c+11 >= u+512)
+ goto r;
+ if (y != č)
+ goto c;
+ if (memcmp(o, ž, y))
+ goto c;
+ if (ntohs(*(uint16_t *) c+1) != A)
+ goto c;
+ if (ntohs(*(uint16_t *) c+3) != In)
+ goto c;
+ if (ntohs(*(uint16_t *) c+5) != 4) /* this is actually a malformed packet, */
+ goto c; /* A resource record must be four bytes */
+ if (n--)
+ goto c;
+ r.s_addr = *(in_addr_t *) c+7;
+ goto r;
+c:
+ c += ntohs(*(uint16_t *) c+5)+7;
+ if (c >= u+512)
+ goto r;
+ continue;
+ }
+r:
+ free(o);
+ return r;
+} /* returns nth IP of A record for domain d of length l in response packet u or 0.0.0.0 for err */
int finish = 0;
int c = -1; /* child process */
void handler () {
@@ -278,6 +325,7 @@ struct timespec lp = { /* last packet */
void child_handler () {
if (clock_gettime(CLOCK_MONOTONIC, &lp) == -1)
perror("clock_gettime(CLOCK_MONOTONIC, &lp)");
+ fprintf(stderr, "recv child received signal\n");
}
int main (int argc, char ** argv) {
int r = 2;
@@ -403,12 +451,14 @@ o:
signal(SIGINT, child_handler);
signal(SIGTERM, child_handler);
while (1) {
- char b[512]; /* max dns packet */
+ char u[512]; /* max dns packet */
struct sockaddr_in f;
socklen_t č = sizeof f;
- if (recvfrom(s,b,512,!lp.tv_sec?MSG_DONTWAIT:0,(struct sockaddr*)&f,&č)==-1){
+ int š;
+ if ((š = recvfrom(s, u, 512, lp.tv_sec ? MSG_DONTWAIT : 0,
+ (struct sockaddr *) &f, &č)) == -1) {
if (errno != EWOULDBLOCK) {
- perror("recvfrom(s,b,512,!lp.tv_sec?MSG_DONTWAIT:0,(str...");
+ perror("recvfrom(s, u, 512, lp.tv_sec ? MSG_DONTWAIT : 0...");
return 1;
}
struct timespec z;
@@ -428,26 +478,36 @@ o:
perror("clock_gettime(CLOCK_MONOTONIC, &lp)");
return 2;
}
+ int ž;
+ if ((ž = logudp(o, f, b, u, š)) < -1) {
+ fprintf(stderr, "logudp(o, f, b, u, š) == %d\n", ž);
+ return 3;
+ }
fprintf(stderr, "received response from %s\n", inet_ntoa(f.sin_addr));
- }
+ } /* TODO: parse the response with parse_a etc above this line (: */
return 0;
}
while (!finish) {
- if (!(t = host(n[i], ++j).s_addr)) {
+ if (!(h = host(n[i], ++j)).s_addr) {
if (++i >= l) {
int s;
fprintf(stderr, "finished sending, waiting for last replies\n");
- kill(c, SIGINT); /* child waits */
+ if (kill(c, SIGINT) == -1) { /* child waits */
+ perror("kill(c, SIGINT)");
+ r = 13;
+ goto r;
+ }
+ c = -1;
if (wait(&s) == -1) {
perror("wait(&s)");
- r = 13;
+ r = 14;
goto r;
}
if (WIFEXITED(s) && !WEXITSTATUS(s)) {
r = 0;
goto r;
}
- r = 14;
+ r = 15;
goto r;
}
else
@@ -467,6 +527,10 @@ o:
.arcount = 0
};
int v = domain2name_len(d, strlen(d));
+ if (v < 0) {
+ r = 16;
+ goto r;
+ }
#define L (sizeof h + v + 2*2)
char * u = alloca(L);
char * c;
@@ -476,9 +540,22 @@ o:
c += domain2name(c, d, strlen(d));
c = (char *) memcpy(c, &y, 2) + 2;
c = (char *) memcpy(c, &k, 2) + 2;
- logudp(o, b, e, u, L);
- sendto(s, u, L, 0, (struct sockaddr *) &e, sizeof(struct sockaddr));
- usleep(t);
+ int ž;
+ if ((ž = logudp(o, b, e, u, L)) < -1) {
+ fprintf(stderr, "logudp(o, b, e, u, L) == %d\n", ž);
+ r = 17;
+ goto r;
+ }
+ if (sendto(s, u, L, 0, (struct sockaddr *) &e, sizeof(struct sockaddr)) == -1) {
+ perror("sendto(s, u, L, 0, (struct sockaddr *) &e, sizeof(struct sockaddr))");
+ r = 18;
+ goto r;
+ }
+ if (usleep(t)) {
+ perror("usleep(t)");
+ r = 19;
+ goto r;
+ }
}
if (finish)
kill(c, SIGTERM); /* stop receiving */
@@ -486,7 +563,7 @@ r:
if (!r && j != -1) {
char * x = alloca(l*31+strlen("SCANNED \n0"));
strcpy(x, "SCANNED ");
- for (int m = 0; m < finish ? i : l; m++) {
+ for (int m = 0; m < (finish ? i : l); m++) {
strcat(x, inet_ntoa(n[m].addr));
strcat(x, "/");
strcat(x, inet_ntoa(n[m].mask));
@@ -501,5 +578,8 @@ r:
if (o != -1)
if (close(o))
perror("close(o)");
+ if (c != -1)
+ if (kill(c, SIGKILL) == -1)
+ perror("kill(c, SIGKILL)");
return r;
}