Introduction
Introduction Statistics Contact Development Disclaimer Help
Initial import of http://galos.no-ip.org/sdhcp - sdhcp - simple dhcp client
git clone git://git.codemadness.org/sdhcp
Log
Files
Refs
LICENSE
---
commit a91f359dd69354befd8c70a89e0effd8891e1644
Author: sin <[email protected]>
Date: Wed, 25 Sep 2013 12:14:00 +0100
Initial import of http://galos.no-ip.org/sdhcp
Diffstat:
A Makefile | 14 ++++++++++++++
A debug.c | 139 ++++++++++++++++++++++++++++++
A sdhcp.8 | 16 ++++++++++++++++
A sdhcp.c | 437 +++++++++++++++++++++++++++++…
4 files changed, 606 insertions(+), 0 deletions(-)
---
diff --git a/Makefile b/Makefile
@@ -0,0 +1,14 @@
+DESTDIR=
+sdhcp: sdhcp.c debug.c
+ $(CC) -O2 -o $@ sdhcp.c -static
+debug: sdhcp.c debug.c
+ $(CC) -DDEBUG -o sdhcp sdhcp.c -static
+
+all: sdhcp
+
+install: all
+ install -s sdhcp $(DESTDIR)/sbin
+ gzip -c sdhcp.8 > /usr/share/man/man8/sdhcp.8.gz
+
+clean:
+ rm -f sdhcp ?*~
diff --git a/debug.c b/debug.c
@@ -0,0 +1,139 @@
+#include<stdarg.h>
+#ifdef DEBUG
+unsigned short nhgets(uchar c[2]){
+ return ((c[0]<<8) + c[1])&0xffff;
+}
+unsigned long nhgetl(uchar c[4]){
+ return (nhgets(c)<<16) + nhgets(c+2);
+}
+char *ipstr(uchar *ip){
+ char * ch = malloc(3*4+3+10);
+ sprintf(ch, "%d.%d.%d.%d", ip[0],ip[1],ip[2],ip[3]);
+ return ch;
+}
+#endif
+
+void
+dbgprintf(char *str, ...)
+{
+#ifdef DEBUG
+ va_list ap;
+ va_start(ap, str);
+ vfprintf(stderr, str, ap);
+ va_end(ap);
+#endif
+}
+
+void
+bpdump(uchar *p, int n)
+{
+#ifdef DEBUG
+ int len, i, code;
+ Bootp *bp;
+// Udphdr *up;
+
+ bp = (Bootp*)p;
+ // up = (Udphdr*)bp->udphdr;
+
+ if(n < bp->magic - p) {
+ fprintf(stderr, "dhcpclient: short bootp packet");
+ return;
+ }
+ char *types[] = {"discover", "offer", "request",
+ "decline", "ack", "nak", "release", "inform"};
+ uchar type;
+ optget(bp, &type, ODtype, sizeof type);
+ fprintf(stderr, "DHCP%s\n", types[type-1]);
+ // fprintf(stderr, "laddr=%I lport=%d raddr=%I rport=%d\n", up->laddr,
+ // nhgets(up->lport), up->raddr, nhgets(up->rport));
+ fprintf(stderr, "op=%d htype=%d hlen=%d hops=%d\n", *bp->op, *bp->htype,
+ * bp->hlen, *bp->hops);
+ fprintf(stderr, "xid=%x secs=%d flags=%x\n", nhgetl(bp->xid),
+ nhgets(bp->secs), nhgets(bp->flags));
+ fprintf(stderr, "ciaddr=%s yiaddr=%s siaddr=%s giaddr=%s\n",
+ ipstr(bp->ciaddr), ipstr(bp->yiaddr), ipstr(bp->siaddr), ipstr(bp->…
+ fprintf(stderr, "chaddr=");
+ for(i=0; i<15; i++)
+ fprintf(stderr, "%.2x:", bp->chaddr[i]);
+ fprintf(stderr, "%.2x\n", bp->chaddr[15]);
+ fprintf(stderr, "sname=%s\n", bp->sname);
+ fprintf(stderr, "file = %s\n", bp->file);
+
+ n -= bp->magic - p;
+ p = bp->magic;
+
+ if(n < 4)
+ return;
+ if(memcmp(magic, p, 4) != 0)
+ fprintf(stderr, "dhcpclient: bad opt magic %#x %#x %#x %#x\n",
+ p[0], p[1], p[2], p[3]);
+ p += 4;
+ n -= 4;
+
+ while(n>0) {
+ code = *p++;
+ n--;
+ if(code == OBpad)
+ continue;
+ if(code == OBend)
+ break;
+ if(n == 0) {
+ fprintf(stderr, " bad option: %d", code);
+ return;
+ }
+ len = *p++;
+ n--;
+ if(len > n) {
+ fprintf(stderr, " bad option: %d", code);
+ return;
+ }
+ switch(code) {
+ default:
+ fprintf(stderr, "unknown option %d\n", code);
+ for(i = 0; i<len; i++)
+ fprintf(stderr, "%x ", p[i]);
+ fprintf(stderr, "\n");
+ break;
+ case ODtype:
+ fprintf(stderr, "DHCP type %d\n", p[0]);
+ break;
+ case ODclientid:
+ fprintf(stderr, "client id=");
+ for(i = 0; i<len; i++)
+ fprintf(stderr, "%x ", p[i]);
+ fprintf(stderr, "\n");
+ break;
+ case ODlease:
+ fprintf(stderr, "lease=%d sec\n", nhgetl(p));
+ break;
+ case ODserverid:
+ fprintf(stderr, "server id=%s\n", ipstr(p));
+ break;
+ case OBmask:
+ fprintf(stderr, "mask=%s\n", ipstr(p));
+ break;
+ case OBrouter:
+ fprintf(stderr, "router=%s\n", ipstr(p));
+ break;
+ case ODipaddr:
+ fprintf(stderr, "ip addr=%s\n", ipstr(p));
+ break;
+ case OBdnsserver:
+ fprintf(stderr, "dns=%s\n", ipstr(p));
+ break;
+ case OBbaddr:
+ fprintf(stderr, "broadcast=%s\n", ipstr(p));
+ break;
+ case ODrenewaltime:
+ fprintf(stderr, "renew time=%d sec\n", nhgetl(p));
+ break;
+ case ODrebindingtime:
+ fprintf(stderr, "rebind time=%d sec\n", nhgetl(p));
+ break;
+ }
+ p += len;
+ n -= len;
+ }
+#endif
+ }
+
diff --git a/sdhcp.8 b/sdhcp.8
@@ -0,0 +1,16 @@
+.TH SDHCP 1
+.SH NAME
+sdhcp \- a simple dhcp client
+.SH SYNOPSIS
+.B sdhcp
+.RB [interface]
+.SH DESCRIPTION
+sdchp is a simple, tiny dhcp client. It runs until it enters the "Bound"
+state, then forks to the background and runs as a daemon to keep
+the lease alive.
+.SH BUGS
+I'm sure there's plenty. It only currently supports a small subset of
+dhcp options, and has been untested on larger networks. It ignores most of
+the dchp options it understands. Send bug reports to me!
+.SH AUTHOR
+David Galos (galosd83 (at) students.rowan.edu)
diff --git a/sdhcp.c b/sdhcp.c
@@ -0,0 +1,437 @@
+#include<sys/socket.h>
+#include<sys/ioctl.h>
+#include<netinet/in.h>
+#include<net/if.h>
+#include<net/route.h>
+#include<signal.h>
+#include<sys/poll.h>
+#include<errno.h>
+#include<fcntl.h>
+#include<stdio.h>
+#include<stdlib.h>
+#include<string.h>
+
+#define MIN(a,b) (((a)<(b))?(a):(b))
+
+typedef unsigned char uchar;
+typedef struct Bootp Bootp;
+struct Bootp {
+ uchar op [1];
+ uchar htype [1];
+ uchar hlen [1];
+ uchar hops [1];
+ uchar xid [4];
+ uchar secs [2];
+ uchar flags [2];
+ uchar ciaddr [4];
+ uchar yiaddr [4];
+ uchar siaddr [4];
+ uchar giaddr [4];
+ uchar chaddr [16];
+ uchar sname [64];
+ uchar file [128];
+ uchar magic [4];
+ uchar optdata [312-4];
+};
+
+void bpdump(uchar *p, int n);
+enum {
+ DHCPdiscover = 1, DHCPoffer, DHCPrequest,
+ DHCPdecline, DHCPack, DHCPnak, DHCPrelease,
+ DHCPinform, Timeout=200,
+
+ Bootrequest= 1,
+ Bootreply= 2,
+ /* bootp flags */
+ Fbroadcast= 1<<15,
+
+ OBpad= 0,
+ OBmask= 1,
+ OBrouter= 3,
+ OBnameserver= 5,
+ OBdnsserver= 6,
+ OBbaddr= 28,
+ ODipaddr= 50, /* 0x32 */
+ ODlease= 51,
+ ODoverload= 52,
+ ODtype= 53, /* 0x35 */
+ ODserverid= 54, /* 0x36 */
+ ODparams= 55, /* 0x37 */
+ ODmessage= 56,
+ ODmaxmsg= 57,
+ ODrenewaltime= 58,
+ ODrebindingtime= 59,
+ ODvendorclass= 60,
+ ODclientid= 61, /* 0x3d */
+ ODtftpserver= 66,
+ ODbootfile= 67,
+ OBend= 255,
+};
+
+enum{ Broadcast, Unicast};
+
+Bootp bp;
+uchar magic[] = {99, 130, 83, 99};
+
+//struct conf{
+ uchar xid[sizeof bp.xid];
+ uchar hwaddr[16];
+ time_t starttime;
+ char *ifname = "eth0";
+ char *cid = "vaio.12340";
+ int sock;
+//} var;
+//struct sav{
+ uchar server[4];
+ uchar client[4];
+ uchar mask[4];
+ uchar router[4];
+ uchar dns[4];
+ unsigned long t1;
+ unsigned long t2;
+//} sav;
+
+#define IP(...) (uchar[4]){__VA_ARGS__}
+
+static void
+die(char *str)
+{
+ perror(str);
+ exit(EXIT_FAILURE);
+}
+
+static void
+hnput(uchar *dst, unsigned long long src, int n)
+{
+ int x;
+ for(x=0; n--; x++)
+ dst[x] = (src>>(n*8))&0xff;
+}
+
+static struct sockaddr
+iptoaddr(uchar ip[4], int port)
+{
+ struct sockaddr_in ifaddr;
+ ifaddr.sin_family=AF_INET;
+ ifaddr.sin_port = htons(port);
+ memcpy(&ifaddr.sin_addr, ip, sizeof ifaddr.sin_addr);
+ return *(struct sockaddr*)&ifaddr;
+}
+
+#define UDPWRAPPER(name, func, port, hack) \
+static int name(uchar ip[4], int fd, void *data, size_t n){\
+ struct sockaddr addr = iptoaddr(ip, port);\
+ int x, y = sizeof addr;\
+ if((x=func(fd, data, n, 0, &addr, hack y))==-1)\
+ die(#func);\
+ return x;\
+}
+UDPWRAPPER(udpsend, sendto, 67, )
+UDPWRAPPER(udprecv, recvfrom, 68, &)
+
+static void
+setip(uchar ip[4], uchar mask[4], uchar gateway[4])
+{
+ int fd, x;
+ struct ifreq ifreq = {0,};
+ struct rtentry rtreq = {0,};
+
+ fd = socket(PF_INET, SOCK_DGRAM, IPPROTO_IP);
+ strcpy(ifreq.ifr_name, ifname);
+ ifreq.ifr_addr = iptoaddr(ip, 0);
+ ioctl(fd, SIOCSIFADDR , &ifreq);
+ ifreq.ifr_netmask = iptoaddr(mask, 0);
+ ioctl(fd, SIOCSIFNETMASK , &ifreq);
+ ifreq.ifr_flags=IFF_UP|IFF_RUNNING|IFF_BROADCAST|IFF_MULTICAST;
+ ioctl(fd, SIOCSIFFLAGS , &ifreq);
+
+ rtreq.rt_flags = (RTF_UP | RTF_GATEWAY);
+ rtreq.rt_gateway = iptoaddr(gateway, 0);
+ rtreq.rt_genmask = iptoaddr(IP(0,0,0,0), 0);
+ rtreq.rt_dst = iptoaddr(IP(0,0,0,0), 0);
+ ioctl(fd, SIOCADDRT , &rtreq);
+
+ close(fd);
+}
+static void
+cat(int dfd, char *src)
+{
+ char buf[4096];
+ int n, sfd = open(src, O_RDONLY);
+ while((n=read(sfd, buf, sizeof buf))>0)
+ write(dfd, buf, n);
+ close(sfd);
+
+}
+//use itoa not sprintf to make dietlibc happy.
+char* itoa(char * str, int x)
+{
+ if(x==0){
+ *str='0';
+ return str+1;
+ }
+ int k = 1;
+ char *ep = str;
+ while(x/k > 0)
+ k*=10;
+ while((k/=10)>=1)
+ *ep++ = '0'+((x/k)%10);
+ *ep = '\0';
+ return str+strlen(str);
+}
+static void
+setdns(uchar dns[4])
+{
+ char buf[128], *bp = buf;
+ int fd = creat("/etc/resolv.conf", 0644);
+ cat(fd, "/etc/resolv.conf.head");
+ memcpy(buf, "\nnameserver ", 12), bp+=11;
+ *(bp=itoa(bp+1, dns[0])) = '.';
+ *(bp=itoa(bp+1, dns[1])) = '.';
+ *(bp=itoa(bp+1, dns[2])) = '.';
+ *(bp=itoa(bp+1, dns[3])) = '\n';
+ *++bp = '\0';
+ write(fd, buf, strlen(buf));
+ cat(fd, "/etc/resolv.conf.tail");
+ close(fd);
+}
+
+static uchar *
+optget(Bootp *bp, void *data, int opt, int n)
+{
+ uchar *p = bp->optdata;
+ uchar *top = ((uchar*)bp)+sizeof *bp;
+ while(p<top){
+ int code = *p++;
+ if(code==OBpad)
+ continue;
+ if(code==OBend || p==top)
+ break;
+ int len = *p++;
+ if(len > top-p)
+ break;
+ if(code==opt){
+ memcpy(data, p, MIN(len, n));
+ return p;
+ }
+ p+=len;
+ }
+}
+
+static uchar *
+optput(uchar *p, int opt, uchar *data, int len)
+{
+ *p++ = opt;
+ *p++ = (uchar)len;
+ memcpy(p, data, len);
+ return p+len;
+}
+static uchar*
+hnoptput(uchar *p, int opt, long long data, int len)
+{
+ *p++=opt;
+ *p++ = (uchar)len;
+ hnput(p, data, len);
+ return p+len;
+}
+#include "debug.c"
+
+static void
+dhcpsend(int type, int how)
+{
+ dbgprintf("\nSending ");
+ memset(&bp, 0, sizeof bp);
+ hnput(bp.op, Bootrequest, 1);
+ hnput(bp.htype, 1, 1);
+ hnput(bp.hlen, 6, 1);
+ memcpy(bp.xid, xid, sizeof xid);
+ hnput(bp.flags, Fbroadcast, sizeof bp.flags);
+ hnput(bp.secs, time(NULL)-starttime, sizeof bp.secs);
+ memcpy(bp.magic, magic, sizeof bp.magic);
+ memcpy(bp.chaddr, hwaddr, sizeof bp.chaddr);
+ uchar *p = bp.optdata;
+ p = hnoptput(p, ODtype, type, 1);
+ p = optput(p, ODclientid, cid, strlen(cid));
+
+ switch(type){
+ case DHCPdiscover:
+ break;
+ case DHCPrequest:
+// memcpy(bp.ciaddr, client, sizeof bp.ciaddr);
+ p = hnoptput(p, ODlease, t1, sizeof t1);
+ p = optput(p, ODipaddr, client, sizeof client);
+ p = optput(p, ODserverid, server, sizeof server);
+ break;
+ case DHCPrelease:
+ memcpy(bp.ciaddr, client, sizeof client);
+ p = optput(p, ODipaddr, client, sizeof client);
+ p = optput(p, ODserverid, server, sizeof server);
+ break;
+ }
+ *p++=OBend;
+ bpdump((void*)&bp, p-(uchar*)&bp);
+ uchar *ip = (how==Broadcast)?IP(255,255,255,255):server;
+ udpsend(ip, sock, &bp, p-(uchar*)&bp);
+}
+
+static int
+dhcprecv()
+{
+ dbgprintf("\nReceiving ");
+ memset(&bp, 0, sizeof bp);
+ struct pollfd pfd = {sock, POLLIN};
+ if(poll(&pfd, 1, -1)==-1){
+ if(errno!=EINTR)
+ die("poll");
+ else
+ return Timeout;
+ }
+ int x = udprecv(IP(255,255,255,255), sock, &bp, sizeof bp);
+ bpdump((void*)&bp, x);
+ uchar type;
+ optget(&bp, &type, ODtype, sizeof type);
+ return type;
+}
+
+static void
+acceptlease()
+{
+ setip(client, mask, router);
+ setdns(dns);
+ alarm(t1);
+}
+
+static void
+run()
+{
+#if 0
+InitReboot:
+ //send DHCPrequest to old server
+ dhcpsend(DHCPrequest, Broadcasr);
+ goto Rebooting;
+Rebooting:
+ switch (dhcprecv()){
+ case DHCPnak:
+ goto Init;
+ case DHCPack:
+ acceptoffer();
+ goto Bound;
+ }
+#endif
+Init:
+ dbgprintf("\n\n------- Init ------\n");
+ dhcpsend(DHCPdiscover, Broadcast);
+ alarm(1);
+ goto Selecting;
+Selecting:
+ dbgprintf("\n\n------- Selecting ------\n");
+ switch(dhcprecv()){
+ case DHCPoffer:
+ alarm(0);
+ memcpy(client, bp.yiaddr, sizeof client);
+ optget(&bp, server, ODserverid, sizeof server);
+ optget(&bp, mask, OBmask, sizeof mask);
+ optget(&bp, router, OBrouter, sizeof router);
+ optget(&bp, dns, OBdnsserver, sizeof dns);
+ optget(&bp, &t1, ODlease, sizeof t1);
+ t1 = ntohl(t1);
+ dhcpsend(DHCPrequest, Broadcast);
+ goto Requesting;
+ case Timeout:
+ goto Init;
+ default:
+ goto Selecting;
+ }
+Requesting:
+ dbgprintf("\n\n------- Requesting ------\n");
+ switch(dhcprecv()){
+ case DHCPoffer:
+ goto Requesting; //ignore other offers.
+// case DHCPack: //(and you don't want it)?
+// dhcpsend(DHCPdecline, Unicast);
+// goto Init;
+ case DHCPack:
+ acceptlease();
+ goto Bound;
+ }
+Bound:
+ dbgprintf("\n\n------- Bound ------\n");
+ write(1, "Congrats! You should be on the 'net.\n", 37);
+ if(fork())
+ exit(0);
+ switch (dhcprecv()){
+ case DHCPoffer:
+ case DHCPack:
+ case DHCPnak:
+ goto Bound; //discard offer, ack, or nak
+ case Timeout:
+ dhcpsend(DHCPrequest, Unicast);
+ goto Renewing;
+ }
+Renewing:
+ dbgprintf("\n\n------- Renewing ------\n");
+ switch(dhcprecv()){
+ case DHCPack:
+ acceptlease();
+ goto Bound;
+ case DHCPnak:
+ //halt network;
+ goto Init;
+ case Timeout: //t2 expires:
+ dhcpsend(DHCPrequest, Broadcast);
+ goto Rebinding;
+ }
+Rebinding:
+ dbgprintf("\n\n------- Rebinding ------\n");
+ switch(dhcprecv()){
+ case DHCPnak: //lease expired
+ //halt network;
+ goto Init;
+ case DHCPack:
+ acceptlease();
+ goto Bound;
+ }
+}
+
+static void nop(int unused){ }
+static void cleanexit(int unused){
+ dhcpsend(DHCPrelease, Unicast);
+ exit(0);
+}
+
+int
+main(int argc, char *argv[])
+{
+ if(argc>2){
+ write(2, "usage: sdhcp [inferface]\n",25);
+ exit(EXIT_FAILURE);
+ }if(argc==2)
+ ifname = argv[1];
+
+ signal(SIGALRM, nop);
+ signal(SIGTERM, cleanexit);
+
+ if((sock = socket(AF_INET, SOCK_DGRAM, 0)) == -1)
+ die("socket");
+ int bcast = 1;
+ if(setsockopt(sock, SOL_SOCKET, SO_BROADCAST, &bcast, sizeof bcast)==-…
+ die("setsockopt");
+ struct ifreq ifreq = {0,};
+ strcpy(ifreq.ifr_name, ifname);
+ ioctl(sock, SIOCGIFINDEX, &ifreq);
+ if(setsockopt(sock, SOL_SOCKET, SO_BINDTODEVICE, &ifreq, sizeof ifreq)…
+ die("setsockopt");
+ struct sockaddr addr = iptoaddr(IP(255,255,255,255), 68);
+ if(bind(sock, (void*)&addr, sizeof addr)!=0)
+ die("bind");
+ ioctl(sock, SIOCGIFHWADDR, &ifreq);
+ memcpy(hwaddr, ifreq.ifr_hwaddr.sa_data, sizeof ifreq.ifr_hwaddr.sa_da…
+ int rnd = open("/dev/urandom", O_RDONLY);
+ read(rnd, xid, sizeof xid);
+ close(rnd);
+
+ starttime = time(NULL);
+ run();
+ return 0;
+}
+
You are viewing proxied material from codemadness.org. The copyright of proxied material belongs to its original authors. Any comments or complaints in relation to proxied material should be directed to the original authors of the content concerned. Please see the disclaimer for more details.