netd: add ping client (to test raw socks)
authorBrett Gordon <beretta42@gmail.com>
Tue, 24 Jan 2017 15:59:19 +0000 (10:59 -0500)
committerBrett Gordon <beretta42@gmail.com>
Tue, 24 Jan 2017 15:59:19 +0000 (10:59 -0500)
Applications/netd/Makefile.6809
Applications/netd/ping.c [new file with mode: 0644]

index 0ab7971..af4d166 100644 (file)
@@ -16,7 +16,7 @@ CRT0 = ../../Library/libs/crt0_6809.o
 .SUFFIXES: .c .o
 
 SRCS  = netd.c uip.c uiplib.c timer.c clock-arch.c uip_arp.c telnet.c lwwire.c
-SRCS += echoping.c dig.c gethostbyname.c httpd.c coconic.c
+SRCS += echoping.c dig.c gethostbyname.c httpd.c coconic.c ping.c
 
 OBJS = $(SRCS:.c=.o)
 
@@ -32,6 +32,7 @@ netd: $(OBJS)
        $(LINKER) $(LINKER_OPT) -o echoping $(CRT0) echoping.o
        $(LINKER) $(LINKER_OPT) -o dig $(CRT0) dig.o
        $(LINKER) $(LINKER_OPT) -o httpd $(CRT0) httpd.o
+       $(LINKER) $(LINKER_OPT) -o ping $(CRT0) ping.o gethostbyname.o
 
 
 
diff --git a/Applications/netd/ping.c b/Applications/netd/ping.c
new file mode 100644 (file)
index 0000000..4e3e0b0
--- /dev/null
@@ -0,0 +1,189 @@
+/*
+  A Cheesey ipv4 ping client
+
+  todo:
+  * add timestamp to packets to measure delta-t
+  * add time max/min/avg/sdev stats like real ping
+  * check for endian problems
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <signal.h>
+#include <time.h>
+#include "netdb.h"
+
+#define AF_INET     1
+#define SOCK_RAW    1
+
+struct ip {
+    uint8_t ver;
+    uint8_t tos;
+    uint16_t len;
+    uint16_t id;
+    uint16_t off;
+    uint8_t ttl;
+    uint8_t proto;
+    uint16_t cksum;
+    uint32_t src;
+    uint32_t dest;
+};
+
+struct icmp {
+    uint8_t type;
+    uint8_t code;
+    uint16_t cksum;
+    uint16_t id;
+    uint16_t seq;
+};
+
+char *data = "FUZIX ping client";
+
+#define MAXBUF 256
+int fd;
+char buf[MAXBUF];
+struct sockaddr_in addr;
+int id;
+int seq=0;
+int sent=0;
+int recv=0;
+
+void alarm_handler( int signum ){
+    return;
+}
+
+void int_handler( int signum ){
+    printf("sent %d, recv %d, %d%%\n",
+          sent, recv, recv*100/sent );
+    exit(0);
+}
+
+/* print a IP address */
+void ipprint( uint32_t *a ){
+    char *b = (char *)a;
+    printf("%d.%d.%d.%d", b[0], b[1], b[2], b[3] );
+}
+
+
+/* returns inet chksum */
+uint16_t cksum( char *b, int len ){
+    uint16_t sum = 0;
+    uint16_t t;
+    char *e = b + len;
+    b[len] = 0;
+    while(b < e){
+       t = (b[0] << 8) + b[1];
+       sum += t;
+       if(sum < t) sum++;
+       b += 2;
+    }
+    return ~sum;
+}
+
+
+/* sends ping to remote */
+void send( void ){
+    struct icmp *i = (struct icmp *)buf;
+    int l = strlen(data) + 8;
+    memset( buf, 0, MAXBUF);
+    i->type = 8;  // echo request
+    i->id = id;
+    i->seq = seq;
+    strcpy( &buf[8], data );
+    i->cksum = cksum(buf, l);
+    write(fd, buf, l);
+    sent++;
+    seq++;
+}
+
+my_open( int argc, char *argv[]){
+    struct hostent *h;
+
+    h=gethostbyname( argv[1] );
+    if( ! h ){
+       fprintf( stderr, "cannot resolve hostname\n" );
+       exit(1);
+    }
+    memcpy( &addr.sin_addr.s_addr, h->h_addr_list[0], 4 );
+
+    fd = socket(AF_INET, SOCK_RAW, 1);
+    if (fd < 0) {
+       perror("af_inet sock_stream 0");
+       exit(1);
+    }
+
+    /* fuzix raw sockets (for now) repurposes the connect() 
+       address struct to pass it's protocol number
+     */  
+    addr.sin_port = 1;  
+    addr.sin_family = AF_INET;
+    if (connect(fd, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
+       perror("connect");
+       exit(1);
+    }
+}
+
+
+int main( int argc, char *argv[] ){
+    uint16_t c = 0;
+    int x,i;
+    time_t t;
+    struct icmp *icmpbuf;
+    struct ip *ipbuf;
+    struct ip *ipbuf2;
+
+    srand(time(&t));
+    id = rand();
+
+    signal(SIGINT, int_handler);
+
+    if( argc < 2 ){
+       fprintf( stderr,"usage: ping hostname\n");
+       exit(1);
+    }
+
+    my_open( argc, argv );
+    
+
+    while(1){
+       send();
+       signal( SIGALRM, alarm_handler );
+       alarm(2);
+    ragain:
+       x=read( fd, buf, MAXBUF);
+       if (x>0){
+           ipbuf = (struct ip *)buf;
+           if (ipbuf->ver >> 4 != 4)
+               goto ragain;
+           icmpbuf = (struct icmp *)(buf + (ipbuf->ver & 15) * 4);
+           /* check for dest unreachable icmp messages */
+           if ( icmpbuf->type == 3 ){
+               /* point to original ip packet in icmp data field */
+               ipbuf2 = (struct ip *)(icmpbuf + 1);
+               icmpbuf = (struct icmp *)((char *)ipbuf2 + (ipbuf2->ver & 15) * 4);
+               /* check the bombed-out ip packet to see if it's ours */
+               if( icmpbuf->id == id ){
+                   printf("ICMP: from ");
+                   ipprint( &ipbuf->src );
+                   printf(" dest unreachable\n");
+               }
+               goto ragain;
+           }   
+           /* filter for our id */
+           if( icmpbuf->id != id )
+               goto ragain;
+           /* passed filters, so this must be one of our pings */
+           recv++;
+           printf("%d bytes from %s (", x, argv[1] );
+           ipprint( &ipbuf->src );
+           printf(") req=%d", icmpbuf->seq );
+           printf("\n");
+       }
+       sleep(1);
+    }
+}