From 71f2037b79a829477a8a41a254c4a2dba9812694 Mon Sep 17 00:00:00 2001 From: Konrad Rosenbaum Date: Wed, 23 Sep 2009 15:39:13 +0000 Subject: [PATCH] started to implement ORO and DNS name list git-svn-id: https://silmor.de/svn/misc/tdhcp@123 752dcaaa-03e5-0310-b894-97e397d490cd --- Makefile | 24 +++++++++++++-- README | 2 +- client.c | 76 +++++++++++++++++++++++++++++++++-------------- common.c | 10 ++++-- common.h | 7 ++++ message.c | 98 +++++++++++++++++++++++++++++++++++++++++++++++++++++++----- message.h | 30 +++++++++++++++++-- 7 files changed, 204 insertions(+), 43 deletions(-) diff --git a/Makefile b/Makefile index ee17413..20c007a 100644 --- a/Makefile +++ b/Makefile @@ -18,9 +18,27 @@ tdhcpd: server.o $(COMMON) $(LD) $(LDFLAGS) -o $@ $^ %.o: %.c - $(CC) $(CFLAGS) -c -o $@ $^ + $(CC) $(CFLAGS) -c -o $@ $< clean: - rm -rf *~ *.o tdhcpc tdhcpd core* + rm -rf *~ *.o core* svnrev.h -.PHONY: clean \ No newline at end of file +distclean: clean + rm -rf tdhcpc tdhcpd .deps + +deps: + rm -f .deps + for i in *.c ; do $(CC) -MM -MG $$i >>.deps ; done + +client.o server.o: svnrev.h +svnrev.h: $(shell ls *.c *.h|grep -v svnrev) + echo "/*Autogenerated File*/" >$@ + echo "#define SVNREV \"`svn info .|grep Revision:|cut -c 11-`\"" >>$@ + +include .deps + +#make empty deps file for non-developers +.deps: + touch .deps + +.PHONY: clean deps \ No newline at end of file diff --git a/README b/README index 429846a..3852898 100644 --- a/README +++ b/README @@ -5,7 +5,7 @@ Tunnel DHCP protected under the GNU GPLv3 or at your option any newer (see COPYING for details) -http://silmor.de/page/tdhcp +http://silmor.de/69 (If there is any significant interest I will create a maillist too.) diff --git a/client.c b/client.c index 9b788b2..09469f9 100644 --- a/client.c +++ b/client.c @@ -24,7 +24,7 @@ const unsigned char SIDEID=1; -char shortopt[]="hl:pPaAdDr:u"; +char shortopt[]="hl:pPaAdDcCr:u"; struct option longopt[]= { {"local-id",1,0,'l'}, {"prefix",0,0,'p'}, @@ -33,42 +33,64 @@ struct option longopt[]= { {"no-addres",0,0,'A'}, {"dns",0,0,'d'}, {"no-dns",0,0,'D'}, + {"rapid-commit",0,0,'c'}, + {"no-rapid-commit",0,0,'C'}, {"retries",1,0,'r'}, {"help",0,0,'h'}, {"duid",1,0,'u'}, {0,0,0,0} }; +#include "svnrev.h" #define HELP \ "Usage: %s [options] device script\n" \ - "\tdevice: a network device (eg. eth0, ppp0, tun0)\n" \ - "\tscript: a script that is executed after fetching parameters\n" \ + "TDHCPc - Tunnel/Tiny DHCP client, revision " SVNREV "\n"\ + "(c) Konrad Rosenbaum, 2009\n"\ + "this program is protected under the GNU GPLv3 or at your option any newer\n"\ + "\n"\ + "TDHCP client parameters:\n"\ + " device: a network device (eg. eth0, ppp0, tun0)\n" \ + " script: a script that is executed after fetching parameters\n" \ + " the script receives variables depending on what data is available:\n"\ + " $DNS - comma-separated list of DNS servers\n"\ + " $IPADDR - comma-separated list of assigned IP addresses\n"\ + " $PREFIX - comma-separated list of assigned prefixes\n"\ + " the script may be called several times with different variables\n"\ + "\n"\ "TDHCP client options:\n" \ - "\t-h | --help\n" \ - "\t\tdisplays this help text and exit\n" \ + " -h | --help\n" \ + " displays this help text and exit\n" \ \ - "\t-p | --prefix\n\t-P | --no-prefix\n" \ - "\t\tenables (-p) or disables (-P) fetching a prefix\n" \ + " -p | --prefix\n -P | --no-prefix\n" \ + " enables (-p) or disables (-P) fetching a prefix\n" \ \ - "\t-a | --address\n\t-A | --no-address\n" \ - "\t\tenables (-a) or disables (-A) fetching an address\n" \ + " -a | --address\n -A | --no-address\n" \ + " enables (-a) or disables (-A) fetching an address\n" \ \ - "\t-d | --dns\n\t-D | --no-dns\n"\ - "\t\tenables (-d) or disables (-D) fetching DNS server addresses\n" \ + " -d | --dns\n -D | --no-dns\n"\ + " enables (-d) or disables (-D) fetching DNS server addresses\n" \ \ - "\t-l ID | --local-id=ID\n" \ - "\t\tset the local ID from which the DUID is calculated\n" \ + " -c | --rapid-commit\n -C | --no-rapid-commit\n"\ + " enables (-c) or disables (-C) rapid commit\n"\ + " when enabled, the client attempts to use the quicker\n"\ + " two-phase rapid commit exchange, when disable it uses\n"\ + " the normal four-phase exchange\n"\ + " not all DHCPv6 servers support rapid commit\n"\ \ - "\t-r num | --retries=num\n" \ - "\t\t number of retries before the client gives up\n" \ + " -l ID | --local-id=ID\n" \ + " set the local ID from which the DUID is calculated\n" \ \ - "\t-u DUID | --duid=DUID\n" \ - "\t\tset hex string as explicit DUID (overrides -l)\n" \ + " -r num | --retries=num\n" \ + " number of retries before the client gives up\n" \ \ - "Defaults: %sget prefix, %sget address, %sget DNS, %i retries\n" + " -u DUID | --duid=DUID\n" \ + " set hex string as explicit DUID (overrides -l)\n" \ + "\n"\ + "Defaults: %sget prefix, %sget address, %sget DNS,\n"\ + " %suse rapid commit, %i retries\n" static char*argv0=0,*localid=0,*device=0,*script=0; -static int getprefix=0,getaddress=0,getdns=1,retries=10; +static int getprefix=0,getaddress=0,getdns=1,retries=10,userapid=1; static void printhelp() { @@ -77,6 +99,7 @@ static void printhelp() getprefix?"":"don't ", getaddress?"":"don't ", getdns?"":"don't ", + userapid?"":"don't ", retries ); } @@ -100,6 +123,8 @@ int main(int argc,char**argv) case 'r':retries=atoi(optarg);break; case 'l':localid=optarg;break; case 'u':setduid(optarg);break; + case 'c':userapid=1;break; + case 'C':userapid=0;break; default: fprintf(stderr,"Syntax error in arguments.\n"); printhelp(); @@ -135,10 +160,15 @@ int main(int argc,char**argv) msg=newmessage(MSG_SOLICIT); settargetserver(&msg->msg_peer); messageaddopt(msg,OPT_CLIENTID); - if(getdns)messageaddopt(msg,OPT_DNS); - if(getaddress)messageaddopt(msg,OPT_IANA); - if(getprefix)messageaddopt(msg,OPT_IAPD); - if(getaddress||getprefix)messageaddopt(msg,OPT_RAPIDCOMMIT); + if(userapid){ + if(getdns){ + messageaddoptrequest(msg,OPT_DNS_SERVER); + messageaddoptrequest(msg,OPT_DNS_NAME); + } + if(getaddress)messageaddopt(msg,OPT_IANA); + if(getprefix)messageaddopt(msg,OPT_IAPD); + messageaddopt(msg,OPT_RAPIDCOMMIT); + } /*start main loop*/ for(c=0;c #include -const unsigned long PEN=0xffffffff; +const unsigned long PEN=0xfedcba21; unsigned char LOCALID[16]={0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0}; int DUIDLEN; @@ -42,15 +42,17 @@ static void dumpduid() static void calcduid() { - DUIDLEN=23; + DUIDLEN=25; DUID[0]=0; DUID[1]=2; /*byte 0+1: DUID Type 0x0002*/ DUID[2]=(PEN>>24)&0xff; DUID[3]=(PEN>>16)&0xff; DUID[4]=(PEN>>8)&0xff; DUID[5]=PEN&0xff; /*byte 2-5: enterprise number*/ - DUID[6]=SIDEID; /*byte 6: client or server*/ - memcpy(DUID+7,LOCALID,16);/*byte 7-22: hash*/ + DUID[6]=0; + DUID[7]=0;/*byte 6,7: project ID 0*/ + DUID[8]=SIDEID; /*byte 8: client or server*/ + memcpy(DUID+9,LOCALID,16);/*byte 9-24: hash*/ dumpduid(); } diff --git a/common.h b/common.h index 0f01e6a..45d1783 100644 --- a/common.h +++ b/common.h @@ -47,4 +47,11 @@ extern int usesyslog; /*tells the log function what level to log (default: LOGINFO)*/ extern int loglevel; + +/*emulate C++ boolean type*/ +#define bool int +#define true 1 +#define false 0 + + #endif diff --git a/message.c b/message.c index 78f454d..c247edc 100644 --- a/message.c +++ b/message.c @@ -34,6 +34,14 @@ struct dhcp_msg* newmessage(int t) return r; } +struct dhcp_opt* newoption(unsigned short t) +{ + struct dhcp_opt*o; + o=malloc(sizeof(struct dhcp_opt)); + memset(o,0,sizeof(struct dhcp_opt)); + return o; +} + static void freeopt(struct dhcp_opt*tgt) { int i; @@ -43,14 +51,18 @@ static void freeopt(struct dhcp_opt*tgt) //copy duid free(tgt->opt_duid.duid); break; - case OPT_DNS: + case OPT_DNS_SERVER: //copy DNS - free(tgt->opt_dns.addr); + free(tgt->opt_dns_server.addr); break; +#warning missing the other DNS here case OPT_STATUS_CODE: //copy message free(tgt->opt_status.message); break; + case OPT_OPTREQUEST: + free(tgt->opt_oro.opt); + break; } /*free sub-options*/ for(i=0;iopt_numopts;i++) @@ -59,6 +71,11 @@ static void freeopt(struct dhcp_opt*tgt) /*wipe*/ memset(tgt,0,sizeof(struct dhcp_opt)); } +void freeoption(struct dhcp_opt*o) +{ + freeopt(o); + free(o); +} void freemessage(struct dhcp_msg*m) { @@ -101,11 +118,12 @@ static void cloneopt(struct dhcp_opt*tgt,struct dhcp_opt*src) tgt->opt_duid.duid=malloc(tgt->opt_duid.len); memcpy(tgt->opt_duid.duid,src->opt_duid.duid,tgt->opt_duid.len); break; - case OPT_DNS: + case OPT_DNS_SERVER: //copy DNS - tgt->opt_dns.addr=malloc(sizeof(struct in6_addr)*tgt->opt_dns.num_dns); - memcpy(tgt->opt_dns.addr,src->opt_dns.addr,sizeof(struct in6_addr)*tgt->opt_dns.num_dns); + tgt->opt_dns_server.addr=malloc(sizeof(struct in6_addr)*tgt->opt_dns_server.num_dns); + memcpy(tgt->opt_dns_server.addr,src->opt_dns_server.addr,sizeof(struct in6_addr)*tgt->opt_dns_server.num_dns); break; +#warning missing dns-name here case OPT_STATUS_CODE: //copy message tgt->opt_status.message=malloc(strlen(src->opt_status.message)+1); @@ -136,6 +154,7 @@ int messageappendopt(struct dhcp_msg*msg,struct dhcp_opt*opt) int optappendopt(struct dhcp_opt*sup,struct dhcp_opt*opt) { + if(!sup || !opt)return -1; if(sup->opt_numopts>=sup->priv_optlen){ sup->priv_optlen+=ALLOCINCR; sup->subopt=realloc(sup->subopt,sizeof(struct dhcp_opt)*sup->priv_optlen); @@ -146,6 +165,54 @@ int optappendopt(struct dhcp_opt*sup,struct dhcp_opt*opt) return sup->opt_numopts++; } +int messageaddoptrequest(struct dhcp_msg*msg,unsigned short o) +{ + int p; + if(!msg)return -1; + p=messagefindoption(msg,OPT_OPTREQUEST); + if(p<0){ + p=messageaddopt(msg,OPT_OPTREQUEST); + if(p<0)return -1; + } + oroaddrequest(&msg->msg_opt[p],o); + return p; +} + +/*add an option request to the ORO option; returns index of the request or -1 on error*/ +int oroaddrequest(struct dhcp_opt*opt,unsigned short oro) +{ + if(!opt)return -1; + if(opt->opt_type!=OPT_OPTREQUEST)return -1; + opt->opt_oro.opt=realloc(opt->opt_oro.opt,(opt->opt_oro.numopts+1)*sizeof(unsigned short)); + opt->opt_oro.opt[opt->opt_oro.numopts]=oro; + return opt->opt_oro.numopts++; +} + +/*checks that the message has a certain option; returns index on success or -1 on error*/ +int messagefindoption(struct dhcp_msg*msg,unsigned short opt) +{ + int i; + if(!msg || !opt)return -1; + for(i=0;imsg_numopts;i++) + if(msg->msg_opt[i].opt_type==opt) + return i; + return -1; +} + +/*checks that the message has an option request option with a certain option requested; returns !=0 on success*/ +bool messagehasoptionrequest(struct dhcp_msg*msg,unsigned short oro) +{ + int i,j; + if(!msg || !oro)return false; + i=messagefindoption(msg,OPT_OPTREQUEST); + if(i<0)return false; + for(j=0;jmsg_opt[i].opt_oro.numopts;j++) + if(msg->msg_opt[i].opt_oro.opt[j]==oro) + return true; + return false; +} + + #define COPYINT4(ptr,i) (ptr)[0]=(i)>>24;(ptr)[1]=((i)>>16)&0xff;(ptr)[2]=((i)>>8)&0xff;(ptr)[3]=(i)&0xff; #define COPYINT2(ptr,i) (ptr)[0]=((i)>>8)&0xff;(ptr)[1]=(i)&0xff; @@ -178,13 +245,21 @@ static void encodeopt(struct dhcp_opt*opt,unsigned char*buf,int*pos,int max) for(l=0;lopt_numopts;l++) encodeopt(&opt->subopt[l],buf,pos,max); break; - case OPT_DNS: - for(l=0;lopt_dns.num_dns;l++){ + case OPT_DNS_SERVER: + for(l=0;lopt_dns_server.num_dns;l++){ *pos+=16; if(*pos>max)return; - memcpy(&buf[*pos],&opt->opt_dns.addr[l],16); + memcpy(&buf[*pos],&opt->opt_dns_server.addr[l],16); } break; + case OPT_DNS_NAME: +# warning - domain encoding please! + /*for(l=0;lopt_dns_name.num_dns;l++){ + *pos+=16; + if(*pos>max)return; + memcpy(&buf[*pos],&opt->opt_dns_server.addr[l],16); + }*/ + break; case OPT_IAADDR: *pos+=24; if(*pos>max)return; @@ -239,7 +314,12 @@ void sendmessage(struct dhcp_msg*msg) int i,pos; if(msg==0)return; /*header*/ - COPYINT4(buf,msg->msg_type) + /*type*/ + buf[0]=msg->msg_type; + /*transaction ID*/ + buf[1]=(msg->msg_id>>16)&0xff; + buf[2]=(msg->msg_id>>8)&0xff; + buf[3]=msg->msg_id&0xff; pos=4; /*options*/ for(i=0;imsg_numopts;i++) diff --git a/message.h b/message.h index 2ef286e..d8f4200 100644 --- a/message.h +++ b/message.h @@ -13,6 +13,7 @@ #ifndef TDHCP_MESSAGE_H #define TDHCP_MESSAGE_H +#include "common.h" #include #include @@ -28,10 +29,12 @@ /*primary options*/ #define OPT_CLIENTID 1 #define OPT_SERVERID 2 -#define OPT_DNS 23 +#define OPT_DNS_SERVER 23 +#define OPT_DNS_NAME 24 #define OPT_IANA 3 #define OPT_IAPD 25 #define OPT_RAPIDCOMMIT 14 +#define OPT_OPTREQUEST 6 /*sub-options*/ #define OPT_IAADDR 5 @@ -70,11 +73,15 @@ struct dhcp_opt{ /*subopts: normally of type IAADDRESS, or IAPREFIX*/ } opt_iana; struct dhcp_opt_ia opt_iapd; - struct dhcp_opt_dns { + struct dhcp_opt_dns_servers { /*number of DNS servers (opt_len/16)*/ int num_dns; struct in6_addr *addr; - } opt_dns; + } opt_dns_server; + struct dhcp_opt_dns_names { + int num_dns; + char**namelist; + } opt_dns_names; struct dhcp_opt_iaaddress { struct in6_addr addr; unsigned long preferred_lifetime,valid_lifetime; @@ -87,6 +94,10 @@ struct dhcp_opt{ unsigned short status; char*message; } opt_status; + struct dhcp_opt_request { + int numopts; + unsigned short *opt; + } opt_oro; }; /*amount of sub-options (eg. OPT_IA*)*/ @@ -122,8 +133,13 @@ struct dhcp_msg { /*allocate a new message of given type*/ struct dhcp_msg* newmessage(int); +/*allocate an option (resets it to zero, sets given type)*/ +struct dhcp_opt* newoption(unsigned short); + /*free a message structure*/ void freemessage(struct dhcp_msg*); +/*free an option structure recursively*/ +void freeoption(struct dhcp_opt*); /*add an option type to the (request) message, returns index*/ int messageaddopt(struct dhcp_msg*,unsigned short); @@ -131,6 +147,14 @@ int messageaddopt(struct dhcp_msg*,unsigned short); int messageappendopt(struct dhcp_msg*,struct dhcp_opt*); /*add a sub-option to an option, returns index*/ int optappendopt(struct dhcp_opt*,struct dhcp_opt*); +/*add an option request to the message, returns index of the ORO option*/ +int messageaddoptrequest(struct dhcp_msg*,unsigned short); +/*add an option request to the ORO option; returns index of the request or -1 on error*/ +int oroaddrequest(struct dhcp_opt*,unsigned short); +/*checks that the message has a certain option; returns index on success or -1 on error*/ +int messagefindoption(struct dhcp_msg*,unsigned short); +/*checks that the message has an option request option with a certain option requested; returns !=0 on success*/ +bool messagehasoptionrequest(struct dhcp_msg*,unsigned short); /*send the message*/ void sendmessage(struct dhcp_msg*); -- 1.7.2.5