./dhid-5.5/000755 000764 000764 00000000000 11015300152 012344 5ustar00dhisdhis000000 000000 ./dhid-5.5/WHATSNEW000644 000764 000764 00000012421 11015270503 013535 0ustar00dhisdhis000000 000000 WHATSNEW in 5.5 =============== In 5.4 the new NAT friendly behaviour was achieved by sending packets with an rport of 0 to the server. In 5.5 this is no longer needed since the server looks at the version number; hence 5.5 packets still go out with rport set, making them compatible with servers of versions 5.3 or lower. This was a small change/correction and 5.5 is a minor update. WHATSNEW in 5.4 =============== DHIS packet messages leaving a host will now leave from the DHIS return port (58800 by default) instead of a randomly assigned port. Messages sent by this client to a server are marked with a return port of 0 in the payload of the DHIS packet which causes the server to reply to the UDP port from which it receives a packet. In other words, the return UDP port is no longer embedded in a DHIS packet but instead is taken by the server from the UDP layer of the network packet. This feature (dhis client) only works with a DHIS server that implements it; hence, a dhisd server of version 5.4 or above is required for a 5.4 client to operate. This feature is particularly useful in systems behind NAT; whereas before a NAT redirect rule to the return DHIS port (58800 by default) was required, with DHIS 5.4 this is no longer required since NAT boxes should keep the UDP state and redirect back to the right host. A new protocol is also implemented with DHID 5.4; instead of waiting for server checks with CHECK_REQ, the client refreshes itself to the server by sending periodic ECHO_REQ packets to it (every refresh period). The server keeps the host online and only brings it offline it it doesn't see any ECHO_REQ packets for up to 3 times the refresh period. WHATSNEW in 5.3 =============== The documentation was updated. DHID can now be executed under any user (not only root) without changes to the code. The pid file default location was changed to /var/run/dhid.pid WHATSNEW in 5.2 =============== BUG: Client crashes when server reply comes from a different IP address than that to which the initial packet had been sent. Fixed. BUG: SIG_CHLD set to SIG_IGN but wait() used. Fixed. SIG_IGN was removed. WHATSNEW Since Release 5.0 ========================== 1) OnCmd and OffCmd options now are executed with the hostid parameter, the local IPv4 dynamic IP address and additional parameters specified in dhid.conf WHATSNEW Since Release 4.0 ========================== 1) Mail relay commands are no longer implemented (CTL4_MXSTART, CTL4_MXEND) 2) Interactive mode is no longer possible 3) The client now supports multiple servers on multiple addresses and/or multiple ports (see dhid.conf.sample) 4) The client now is able to update multiple clients within one server (see dhid.conf.sample) 5) The client may now propose how often it wishes the server to verify connectivity with CHECK_REQs. (see refresh option in dhid.conf.sample) 6) For each record updated (a host entry withing dhid.conf) it is possible to execute external scripts at the times of online and offline transitions. (see OnCmd and OffCmd options in dhid.conf.sample) 7) Pid file can now be specified on command line using the -P option 8) The -p command line option now permits changing of the local UDP port. 9) Server port can now be specified individually in dhid.conf for each record (see ISAddr) 10)ISAddr now accepts an FQDN as well as an IP address WHATSNEW Since Release 3.1 ========================== Two major changes. Release 3 clients can however still connect to an R4 server. 1) The protocol has been redisigned. The old simple broadcast packet has been replaced by a full message exchange process. The client now sends an ECHO_REQ to the server with no information and expects an ECHO_ACK reply (a connection has been established). The client then issues an AUTH_REQ and expects an AUTH_ACK or AUTH_DENY. If insecure mode is used the password is inserted in the AUTH_REQ packet. Otherwise, please see below. When the online stage is achieved the client stands in listening mode. Unlike in DHIS R3, it does not send a broadcast packet, but expects instead a query (CHECK_REQ) from the server, upon which must reply with a CHECK_ACK. If the server doesn't receive CHECK_ACKs for a period of time the host is considered to have become offline. If the client doesn't receive queries for a period of time it returns to poll mode (ECHO_REQs are sent again). 2) Public key security has been introduced (QRC). If selected, after an AUTH_REQ the client expects an AUTH_SY upon which replies with an AUTH_SX for successful authentication. The algorithm is as follows: The client holds a pair of private keys, P and Q. These are long integers both prime and congruent to 3 mod 4. The server keeps the client's public key generated by P * Q. Upon an authentication request the server generates a random number X (relatively prime to N) and calculates its square (mod N) Y. Y is sent back to the client. The client then has to prove that it is able to calculate its square root (mod N) (X) which may only be performed with the two prime factors P and Q. In order to do it, the client calculates the square root mod P and mod Q of Y and applies the Chinese Remainder Theorem to calculate the square root mod N. Having done this, the calculated X is sent back to the server for comparission with the original value. ./dhid-5.5/AUTHORS000644 000764 000764 00000000014 11015264761 013426 0ustar00dhisdhis000000 000000 Joao Cabral ./dhid-5.5/main.c000644 000764 000764 00000022127 11015277402 013453 0ustar00dhisdhis000000 000000 /*- * Copyright (c) 1998-2008 DHIS, Dynamic Host Information System * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * */ #include "dhid.h" extern struct conf_t *base; int rport=DEF_ISPORT; char pid_file[256]; char conf_file[256]; void cmd_fork(char *s) { int pid; int status; if(*s=='\0') return; switch(pid=fork()) { case(-1): syslog(LOG_INFO,"Unable to fork for %s",s); break; case(0): system(s); exit(0); default: waitpid(pid,&status,0); } } void sig_usr2() { struct conf_t *cp; cp=base; while(cp!=NULL) { if(cp->stage==ON_STAGE) { offline_req_t msg; msg.hdr.opcode=OFFLINE_REQ; msg.hdr.hostid=cp->id; msg.sid=cp->sid; if(cp->cserver!=NULL) net_write_message((msg_t *)&msg,cp->cserver->addr,cp->cserver->port); } cp->sid=0; cp->stage=POLL_STAGE; cp->cserver=NULL; cp->timeout=60; { char linecmd[512]; struct in_addr sa; sa.s_addr=cp->laddr; sprintf(linecmd,"%s %d %s %s",cp->off_cmd,cp->id, inet_ntoa((struct in_addr)sa) ,cp->off_cmdp); cmd_fork(linecmd); } cp=cp->next; } syslog(LOG_INFO,"-> Offline (USR2)"); } void sig_term() { struct conf_t *cp; cp=base; while(cp!=NULL) { if(cp->stage==ON_STAGE) { offline_req_t msg; msg.hdr.opcode=OFFLINE_REQ; msg.hdr.hostid=cp->id; msg.sid=cp->sid; if(cp->cserver!=NULL) net_write_message((msg_t *)&msg,cp->cserver->addr,cp->cserver->port); } cp->sid=0; cp->stage=POLL_STAGE; cp->cserver=NULL; cp->timeout=60; { char linecmd[512]; struct in_addr sa; sa.s_addr=cp->laddr; sprintf(linecmd,"%s %d %s %s",cp->off_cmd,cp->id, inet_ntoa((struct in_addr)sa) ,cp->off_cmdp); cmd_fork(linecmd); } cp=cp->next; } free_conf(); syslog(LOG_INFO,"daemon exiting"); unlink(pid_file); exit(0); } void usage(char *argv[]) { printf("Syntax: %s [-h] [-p localport] [-P pid_file] [-f conf_file]\n",argv[0]); exit(0); } void check_message(void) { msg_t msg; int from; struct conf_t *cp; cp=base; if(!net_check_message()) return; if(!net_read_message(&msg,&from)) return; if(msg.hdr.opcode==ECHO_REQ) { echo_ack_t m; m.hdr.opcode=ECHO_ACK; m.oserial=msg.hdr.serial; m.hdr.hostid=msg.hdr.hostid; net_write_message((msg_t *)&m,from,msg.hdr.rport); return; } while(cp!=NULL) { if(cp->id==msg.hdr.hostid) { struct ser_t *sp=NULL; sp=cp->servers; while(sp!=NULL) { if(sp->addr==from && sp->port==msg.hdr.rport) break; sp=sp->next; } if(sp!=NULL) break; } cp=cp->next; } if(cp==NULL) { syslog(LOG_INFO,"dhid: Packet recieved from an unknown server or server port! Ignoring ... "); return; } if(msg.hdr.opcode==AUTH_DENY) { syslog(LOG_ERR,"Authentication failed for %d, retrying ...", msg.hdr.hostid); cp->stage=POLL_STAGE; cp->cserver=NULL; if(!cp->refresh) cp->timeout=POLL_FREQ; else cp->timeout=cp->refresh; return; } if(msg.hdr.opcode==AUTH_ACK) { auth_ack_t *p2; p2=(auth_ack_t *)&msg; if(!cp->refresh) cp->timeout=POLL_FREQ*FAIL_ALLOW; else cp->timeout=cp->refresh*FAIL_ALLOW; cp->stage=ON_STAGE; syslog(LOG_INFO,"[%d] -> Online",msg.hdr.hostid); cp->sid=p2->sid; cp->laddr=p2->raddr; if(cp->on_cmd[0]!='\0') { char linecmd[512]; struct in_addr sa; sa.s_addr=cp->laddr; sprintf(linecmd,"%s %d %s %s",cp->on_cmd,cp->id, inet_ntoa((struct in_addr)sa) ,cp->on_cmdp); cmd_fork(linecmd); } return; } if(msg.hdr.opcode==ECHO_ACK && cp->stage==ON_STAGE) { echo_ack_t *m; m=(echo_ack_t *)&msg; if(m->oserial) { if(!cp->refresh) cp->timeout=POLL_FREQ*FAIL_ALLOW; else cp->timeout=cp->refresh*FAIL_ALLOW; } } if(msg.hdr.opcode==ECHO_ACK && cp->stage==POLL_STAGE) { auth_req_t m; struct ser_t *sp; if(cp->cserver!=NULL) return; sp=cp->servers; while(sp!=NULL) { if(sp->addr==from && sp->port==msg.hdr.rport) break; sp=sp->next; } if(sp==NULL) return; cp->cserver=sp; cp->stage=AUTH_STAGE; if(cp->atype==APASS) strcpy(m.pass,cp->pass); else memset(m.pass,0,16); m.hdr.opcode=AUTH_REQ; m.hdr.hostid=cp->id; m.refresh=cp->refresh; net_write_message((msg_t *)&m,from,msg.hdr.rport); if(!cp->refresh) cp->timeout=POLL_FREQ; else cp->timeout=cp->refresh; return; } #ifdef QRC if(msg.hdr.opcode==AUTH_SY) { mpz_t x1,x2,y,x,n; auth_sendx_t m; auth_sendy_t *mp; char buff[1024]; if(cp->atype!=AQRC) return; mpz_init(x1); mpz_init(x2); mpz_init(y); mpz_init(x); mpz_init(n); mp=(auth_sendy_t *)&msg; memcpy(buff,mp->y,200); buff[200]='\0'; mpz_set_str(y,buff,10); qrc_sqrty(x1,y,cp->authp); qrc_sqrty(x2,y,cp->authq); qrc_crt(y,x1,x2,cp->authp,cp->authq); mpz_clear(x1); mpz_clear(x2); mpz_mul(n,cp->authp,cp->authq); mpz_mod(x,y,n); mpz_clear(y); mpz_clear(n); m.hdr.opcode=AUTH_SX; m.hdr.hostid=cp->id; qrc_fill_str(x,m.x,200); mpz_clear(x); net_write_message((msg_t *)&m,from,msg.hdr.rport); return; } #endif return; } int main(int argc,char *argv[]) { FILE *fp; int c; extern char *optarg; strcpy(conf_file,DHID_CONF); strcpy(pid_file,DHID_PID); while((c=getopt(argc,argv,"hf:p:P:"))!=EOF) switch(c) { case('p'): rport=atoi(optarg); break; case('P'): strncpy(pid_file,optarg,sizeof(pid_file)); break; case('f'): strncpy(conf_file,optarg,sizeof(conf_file)); break; case('h'): usage(argv); default: usage(argv); } close(0); close(1); close(2); setsid(); if(fork()) _exit(0); /* Run in background */ syslog(LOG_INFO,"daemon started"); read_conf(conf_file); if(net_init(rport)) { syslog(LOG_ERR,"failed to open incoming udp socket on port %d", rport); exit(255); } signal(SIGUSR1,SIG_IGN); signal(SIGUSR2,sig_usr2); signal(SIGTERM,sig_term); unlink(pid_file); fp=fopen(pid_file,"w"); if(fp!=NULL) { fprintf(fp,"%d",(int)getpid()); fclose(fp); } for(;;) { struct conf_t *cp; check_message(); cp=base; while(cp!=NULL) { if(cp->stage==POLL_STAGE && cp->timeout<=0) { struct ser_t *sp; echo_req_t m; m.hdr.opcode=ECHO_REQ; m.hdr.hostid=cp->id; sp=cp->servers; while(sp!=NULL) { if(sp->addr==0) { struct hostent *h; if ( (h = gethostbyname(sp->hostname)) != NULL ) memcpy( &sp->addr, h->h_addr, 4 ); else { sp=sp->next; continue; } } net_write_message((msg_t *)&m,sp->addr,sp->port); sp=sp->next; } if(!cp->refresh) cp->timeout=POLL_FREQ; else cp->timeout=cp->refresh; } if(cp->timeout>0) cp->timeout--; if(cp->timeout<=0 && cp->stage==AUTH_STAGE) { cp->stage=POLL_STAGE; cp->cserver=NULL; } if(cp->timeout<=0 && cp->stage==ON_STAGE) { syslog(LOG_INFO,"[%d] -> Offline (timeout)",cp->id); cp->stage=POLL_STAGE; cp->cserver=NULL; { char linecmd[512]; struct in_addr sa; sa.s_addr=cp->laddr; sprintf(linecmd,"%s %d %s %s",cp->off_cmd,cp->id, inet_ntoa((struct in_addr)sa),cp->off_cmdp); cmd_fork(linecmd); } } /* If we haven't reached 0 but are a multiple of the poll frequency, send an echo_req out */ if(cp->timeout>0 && cp->stage==ON_STAGE) { int freq; if(!cp->refresh) freq=POLL_FREQ; else freq=cp->refresh; if(!(cp->timeout % freq)) { struct ser_t *sp; echo_req_t m; m.hdr.opcode=ECHO_REQ; m.hdr.hostid=cp->id; sp=cp->servers; while(sp!=NULL) { if(sp->addr==0) { struct hostent *h; if ( (h = gethostbyname(sp->hostname)) != NULL ) memcpy( &sp->addr, h->h_addr, 4 ); else { sp=sp->next; continue; } } net_write_message((msg_t *)&m,sp->addr,sp->port); sp=sp->next; } } } cp=cp->next; } sleep(1); } } ./dhid-5.5/INSTALL000644 000764 000764 00000005032 11015264761 013414 0ustar00dhisdhis000000 000000 Installation of DHIS Release 5.4 ================================ In order to install dhid (the dynamic host update daemon) please carry out the following steps: 1. Compiling If you want DHIS to operate in secure mode (QRC), install the GNU Multiprecision Library. You may download a version of gmp from the DHIS FTP site on ftp://ftp.dhis.org/pub/dhis/gmp-4.1.tar.gz The Installation of GNU MPL should only require "configure;make;make install" Otherwise, i.e., if you wish DHIS to operate in password mode, edit the Makefile and replace CFLAGS, LFLAGS and LIBS by those commented without reference to gmp or QRC. If your OS is System V edit the Makefile and add -lnsl -lsocket to the LIBS section. Type "make". You should have dhid in the source directory 2. Registration Register for a Dynamic DNS Hostname at the DHIS web site: http://www.dhis.org/ You should receive a configuration template with the DHIS server, an identification number and a password or a set of private keys by email. Paranoid Security: If you're really paranoid about security or simply wish to perform things in a secure way, are using QRC, an alternative procedure is available. Instead of receiving your private keys from DHIS you may wish to generate them yourself and only provide the public key. In order to generate a set of private and public keys for use with dhid in QRC mode: run genkeys and save the output in a file: ./genkeys > mykeys mykeys should now have the public key necessary lines that you should submit on registration. The lines starting with AuthP and AuthQ are your private keys. The lines starting with AuthN are your public key. Insert the private keys in dhid.conf and add the public key to your DHIS service account using. 3. Installation Copy dhid.conf which should have been sent to you by email after registration to /etc/dhid.conf or Create /etc/dhid.conf with at least one record. You need to have a valid HostID, ISAddr (server address) and password or set of keys. Protect it, i.e., chmod 600 /etc/dhid.conf Edit your system's startup script and add a single line calling dhid wherever it is (it runs in background so no & is needed). 4. Run And that's it. You may run the dhid daemon at once simply by executing it, or at boot time through your startup script. For a more detailed description of possible additional options please see dhid.conf.sample available in this distribution. ./dhid-5.5/conf.c000644 000764 000764 00000023100 11015277342 013447 0ustar00dhisdhis000000 000000 /*- * Copyright (c) 1998-2008 DHIS, Dynamic Host Information System * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * */ #include "dhid.h" struct conf_t *base=NULL; extern int rport; void off_nl(char *s) { while(*s!='\0' && *s!='\r' && *s!='\n') s++; *s='\0'; } void strtolower(char *s) { while(*s!='\0') { *s=tolower(*s); s++; } return; } void free_conf(void) { struct conf_t *p; struct ser_t *sp; if(base!=NULL) { p=base->next; #ifdef QRC if(base->atype==AQRC) { mpz_clear(base->authp); mpz_clear(base->authq); } #endif sp=base->servers; while(sp!=NULL) { base->servers=base->servers->next; free(sp); sp=base->servers; } free(base); while(p!=NULL) { base=p; p=p->next; #ifdef QRC if(base->atype==AQRC) { mpz_clear(base->authp); mpz_clear(base->authq); } #endif free(base); } base=NULL; } } void read_conf(char *file) { FILE *fp; char line[1024]; char str[64]; free_conf(); fp=fopen(file,"r"); if(fp==NULL) { syslog(LOG_ERR,"failed to read %s",file); exit(1); } while(fgets(line,1024,fp)!=NULL) { off_nl(line); if(!strcmp(line_entry(1,line),"{")) { /* found a record */ struct conf_t *cp; #ifdef QRC char keyp[1024],keyq[1024]; keyp[0]='\0'; keyq[0]='\0'; #endif cp=base; if(base==NULL) { base=(struct conf_t *)malloc(sizeof(struct conf_t)); if(base==NULL) { syslog(LOG_ERR,"Failed malloc for conf record"); exit(255); } cp=base; } else { cp=base; while(cp->next!=NULL) cp=cp->next; cp->next=(struct conf_t *)malloc(sizeof(struct conf_t)); if(cp->next==NULL) { syslog(LOG_ERR,"Failed malloc for conf record"); exit(255); } cp=cp->next; } /* cp now points to a clear record */ /* initialising cp */ cp->id=0; cp->pass[0]='\0'; cp->atype=0; cp->servers=NULL; cp->cserver=NULL; cp->sid=0; cp->laddr=0; cp->next=NULL; cp->refresh=0; cp->stage=POLL_STAGE; cp->timeout=-1; cp->on_cmd[0]='\0'; cp->on_cmdp[0]='\0'; cp->off_cmd[0]='\0'; cp->off_cmdp[0]='\0'; while(fgets(line,1024,fp)!=NULL) { off_nl(line); strtolower(line); if(!strcmp(line_entry(1,line),"}")) break; /* end of record */ if(!strcmp(line_entry(1,line),"hostid")) cp->id=atoi(line_entry(2,line)); if(!strcmp(line_entry(1,line),"hostpass")) { strcpy(cp->pass,line_entry(2,line)); cp->atype=APASS; } if(!strcmp(line_entry(1,line),"isaddr")) { char str2[256]; char str3[256]; struct ser_t *sp; if(cp->servers==NULL) { cp->servers=(struct ser_t *)malloc(sizeof(struct ser_t)); if(cp->servers==NULL) continue; sp=cp->servers; } else { sp=cp->servers; while(sp->next!=NULL) sp=sp->next; sp->next=(struct ser_t *)malloc(sizeof(struct ser_t)); if(sp->next==NULL) continue; sp=sp->next; } sp->next=NULL; sp->port=DEF_ISPORT; sp->addr=0; sp->hostname[0]='\0'; strcpy(str2,line_entry(2,line)); strcpy(str,dot_entry(1,str2)); strcpy(str3,dot_entry(2,str2)); if(isdigit(str[0])) sp->addr=inet_addr(str); else strcpy(sp->hostname,str); if(str3[0]!='\0') sp->port=atoi(str3); } if(!strcmp(line_entry(1,line),"refresh")) { strcpy(str,line_entry(2,line)); cp->refresh=atoi(str); if(cp->refresh<60) cp->refresh=60; } if(!strcmp(line_entry(1,line),"oncmd")) { strcpy(cp->on_cmd,line_entry(2,line)); strcpy(cp->on_cmdp,line_ptr(3,line)); } if(!strcmp(line_entry(1,line),"offcmd")) { strcpy(cp->off_cmd,line_entry(2,line)); strcpy(cp->off_cmdp,line_ptr(3,line)); } if(!strcmp(line_entry(1,line),"authp")) { #ifdef QRC strcat(keyp,line_entry(2,line)); cp->atype=AQRC; #else syslog(LOG_ERR,"QRC authentication not available in this client" ); syslog(LOG_ERR,"Please compile QRC support. Exiting ..."); exit(255); #endif } if(!strcmp(line_entry(1,line),"authq")) { #ifdef QRC strcat(keyq,line_entry(2,line)); cp->atype=AQRC; #else syslog(LOG_ERR,"QRC authentication not available in this client" ); syslog(LOG_ERR,"Please compile QRC support. Exiting ..."); exit(255); #endif } } /* end of record while */ /* Parameter sanity check */ if(cp->atype==0) { syslog(LOG_ERR,"Failed to read authentication key"); exit(255); } if(cp->atype==APASS && cp->pass[0]=='\0') { syslog(LOG_ERR,"Failed to read text authentication key"); exit(255); } #ifdef QRC if(cp->atype==AQRC && (keyp[0]=='\0' || keyq[0]=='\0')) { syslog(LOG_ERR,"Failed to read QRC authentication keys"); exit(255); } #endif if(cp->id==0) { syslog(LOG_ERR,"Failed to read host id"); exit(255); } if(cp->servers==NULL) { syslog(LOG_ERR,"Failed to read remote server address"); exit(255); } #ifdef QRC if(cp->atype==AQRC) { mpz_init(cp->authp); mpz_init(cp->authq); mpz_set_str(cp->authp,keyp,10); mpz_set_str(cp->authq,keyq,10); } #endif } /* close record */ } /* close file read while */ fclose(fp); if(base==NULL) { syslog(LOG_ERR,"No records configured in dhid.conf ... exiting ..."); exit(255); } return; } char *line_entry(int idx,char *buff) { static char b2[1024],*pb2; int i; idx--; b2[0]='\0'; pb2=b2; while((*buff==' ' || *buff=='\t') && *buff!='\0' && *buff!='\n') buff++; if(*buff=='\0' || *buff=='\n') return(b2); for(i=0;i #include #include #include #ifdef QRC #include /* qrc_random() - Generates a random integer of n digits * n may be up to 1024 */ void qrc_random(mpz_t x,int n) { char buff[1024],temp[128]; static int seed=0; if(!seed) { seed++; srandom(time(NULL)); } memset(buff,0,256); memset(temp,0,128); do { sprintf(temp,"%lu",(unsigned long int)random()); strcat(buff,temp); } while(strlen(buff) < n); buff[n]='\0'; mpz_set_str(x,buff,10); return; } /* qrc_genkey() - Generates an integer of 100 digits being congruent * to 3 mod 4 * */ void qrc_genkey(mpz_t k) { int flag=1; do { mpz_t a,b; /* Get a prime number */ do qrc_random(k,100); while(!mpz_probab_prime_p(k,5)); /* Now see if it is congruent to 3 mod 4 */ mpz_init(a);mpz_init(b); mpz_set_ui(a,4); mpz_mod(b,k,a); mpz_set_ui(a,3); if(!mpz_cmp(a,b)) flag=0; mpz_clear(a); mpz_clear(b); } while(flag); } void show_key(mpz_t key,int n,char *s) { char buff[1024]; char chunk[128]; char *cp; int i; mpz_get_str(buff,10,key); cp=buff; for(i=0;ihdr.opcode; swap_msg((int *)&(p->hdr),5); if(mode==2) opcode=p->hdr.opcode; switch(opcode) { case(ECHO_REQ): break; case(ECHO_ACK): { echo_ack_t *p2; p2=(echo_ack_t *)p; swap_int((int *)&(p2->oserial)); break; } case(AUTH_REQ): { auth_req_t *p2; p2=(auth_req_t *)p; swap_int((int *)&(p2->refresh)); break; } case(AUTH_ACK): { auth_ack_t *p2; p2=(auth_ack_t *)p; swap_int((int *)&(p2->sid)); break; } case(AUTH_DENY): break; case(AUTH_SX): break; case(AUTH_SY): break; case(CHECK_REQ): { check_req_t *p2; p2=(check_req_t *)p; swap_int((int *)&(p2->next_check)); break; } case(CHECK_ACK): { check_ack_t *p2; p2=(check_ack_t *)p; swap_int((int *)&(p2->sid)); break; } case(OFFLINE_REQ): { offline_req_t *p2; p2=(offline_req_t *)p; swap_int((int *)&(p2->sid)); break; } } return; } int get_serial(void) { static int s=0; return(++s); } /* * net_init() - Initialises the socket descriptor for receiving * UDP connections * * Updates: udp_sock only * * Returns: 0 on success, 1 on error * */ int net_init(int port) { struct sockaddr_in sa; /* Create UDP socket */ udp_sock=socket(AF_INET,SOCK_DGRAM,0); if(udp_sock<0) return(1); /* Bind the UDP socket */ sa.sin_family=AF_INET; sa.sin_port=htons(port); sa.sin_addr.s_addr=INADDR_ANY; if(bind(udp_sock,(struct sockaddr *)&sa,sizeof(struct sockaddr_in))) { close(udp_sock); return(1); } /* UDP socket is ready to receive messages */ return(0); } /* * net_close() - Closes sockets associated with UDP incoming ports * * Updates: udp_sock only * * Returns: 0 * */ int net_close(void) { close(udp_sock); return(0); } /* * net_check_message() - Returns 1 if there is a message to be read or 0 * otherwise. * */ int net_check_message(void) { fd_set readfds; struct timeval tv; /* Prepare for select */ FD_ZERO(&readfds); FD_SET(udp_sock,&readfds); tv.tv_sec=0; tv.tv_usec=0; /* Check for new messages */ if(select(udp_sock+1,&readfds,NULL,NULL,&tv)==-1) return(0); if(!FD_ISSET(udp_sock,&readfds)) return(0); return(1); } /* * net_read_message() - Reads a message into *p and returns length read * or 0 on error. * */ int net_read_message(msg_t *p,int *from) { int n; socklen_t sl; struct sockaddr_in sa; /* Read message */ sl=sizeof(struct sockaddr_in); n=recvfrom(udp_sock,p,MAX_MSG,0,(struct sockaddr *)&sa,&sl); if(n<=0 || n >MAX_MSG) return(0); /* Convert to big endian if necessary */ if(little_endian()) convert_message(p,2); memcpy(from,&sa.sin_addr,sizeof(struct in_addr)); return(n); } /* * net_write_message() - Writes a message from *p and returns the number of * bytes sent or 0 on error. * */ int net_write_message(msg_t *p,int toaddr,int toport) { struct sockaddr_in sa; int len; int r; p->hdr.version=DHIS_VERSION; p->hdr.serial=get_serial(); /* set destination */ sa.sin_family=AF_INET; sa.sin_port=htons(toport); sa.sin_addr.s_addr=toaddr; /* Get message size */ len=msg_size_by_opcode(p->hdr.opcode); /* Convert to big endian if necessary */ if(little_endian()) convert_message(p,1); /* Send message request */ r=sendto(udp_sock,(unsigned char *)p,len,0,(struct sockaddr *)&sa, sizeof(struct sockaddr_in)); /* Convert back just in case */ if(little_endian()) convert_message(p,2); return(r); } #ifdef QRC /* qrc_random() - Generates a random integer of n digits * n may be up to 1024 */ void qrc_random(mpz_t x,int n) { char buff[1024],temp[128]; static int seed=0; if(!seed) { seed++; srandom(time(NULL)); } memset(buff,0,256); memset(temp,0,128); do { sprintf(temp,"%u",(unsigned)random()); strcat(buff,temp); } while(strlen(buff) < n); buff[n]='\0'; mpz_set_str(x,buff,10); return; } /* qrc_genkey() - Generates an integer of 100 digits being congruent * to 3 mod 4 * */ void qrc_genkey(mpz_t k) { int flag=1; do { mpz_t a,b; /* Get a prime number */ do qrc_random(k,100); while(!mpz_probab_prime_p(k,5)); /* Now see if it is congruent to 3 mod 4 */ mpz_init(a);mpz_init(b); mpz_set_ui(a,4); mpz_mod(b,k,a); mpz_set_ui(a,3); if(!mpz_cmp(a,b)) flag=0; mpz_clear(a); mpz_clear(b); } while(flag); } /* qrc_genx() - Geretates a random x relatively prime to n * */ void qrc_genx(mpz_t x,mpz_t n) { int i; mpz_t t; i=mpz_sizeinbase(n,10); /* Get size of n and take 1 */ i--; mpz_init(t); do { /* Generate x of n-1 digits */ qrc_random(x,i); qrc_geny(t,x,n); /* square it modulo n to get */ mpz_set(x,t); /* quadractic residue */ mpz_gcd(t,x,n); } while(mpz_cmp_ui(t,1)); /* test relative primeness */ mpz_clear(t); } /* qrc_geny() - y is the quadractic residue given by x^2 mod n * */ void qrc_geny(mpz_t y,mpz_t x,mpz_t n) { mpz_powm_ui(y,x,2,n); } /* qrc_sqrty() - Calculates the square root of y mod k using a^((k+1)/4))mod k * */ void qrc_sqrty(mpz_t s,mpz_t y,mpz_t k) { mpz_t t1,t2,t3; mpz_init(t1); mpz_init(t2); mpz_init(t3); mpz_set(t1,k); mpz_set_ui(t3,4); mpz_add_ui(t2,t1,1); /* t2 = k+1 */ mpz_divexact(t1,t2,t3); /* t1 = t2/4 */ mpz_powm(s,y,t1,k); mpz_clear(t1); mpz_clear(t2); mpz_clear(t3); } /* qrc_crt() - Applies the Chinese remainder theorem and calculates x * */ void qrc_crt(mpz_t x,mpz_t xp,mpz_t xq,mpz_t p,mpz_t q) { mpz_t s,t,g1,g2; mpz_t temp; mpz_init(s); mpz_init(t); mpz_init(g1); mpz_init(g2); mpz_init(temp); /* Use Euclid's theorem to find s and t */ mpz_gcdext(g1,s,t,q,p); mpz_mul(temp,xp,s); /* Do g1 = x1.s.q */ mpz_mul(g1,temp,q); mpz_mul(temp,xq,t); /* Do g2 = x2.t.p */ mpz_mul(g2,temp,p); mpz_add(x,g1,g2); /* Do x = g1 + g2 */ mpz_clear(temp); mpz_clear(s); mpz_clear(t); mpz_clear(g1); mpz_clear(g2); } /* qrc_fill_str() - This function fills a buffer pointed by str * with n digits of x. Adds 0's to the left if * required. */ void qrc_fill_str(mpz_t x,char *str,int n) { int i,j; char buff[1024]; char buff2[1024]; char *cp1,*cp2; i=mpz_sizeinbase(x,10); /* Get size of x */ j=n-i; /* j = number of 0's to add */ if(j<0) return; buff[0]='\0'; for(i=0;i OffCmd /etc/dhid-offline.sh } ./dhid-5.5/CONTRIBUTORS000644 000764 000764 00000000234 11015270255 014235 0ustar00dhisdhis000000 000000 Peder Fugl Ian Chilton Nuno Rodriges Jonas Jochum Dan Christensen Ray Burkholder (SIGCHLD bug) Lucas Di PentiMa (Multihomed server client bug) Guus Sliepen ./dhid-5.5/Makefile000644 000764 000764 00000004121 11015277437 014025 0ustar00dhisdhis000000 000000 # - # Copyright (c) 1998-2008 DHIS, Dynamic Host Information System # All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: # 1. Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # 2. Redistributions in binary form must reproduce the above copyright # notice, this list of conditions and the following disclaimer in the # documentation and/or other materials provided with the distribution. # # THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE # ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS # OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) # HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY # OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF # SUCH DAMAGE. # CC=cc # # For password mode only (no QRC), remove the -DQRC=1 statement # CFLAGS=-I/usr/local/include -Wall CFLAGS=-I/usr/local/include -DQRC=1 -Wall LFLAGS=-L/usr/local/lib # For password mode only (no QRC), comment the following line and keep LIBS # empty. # Add -lnsl and -lsocket to LIBS in SysV systems (e.g. Solaris) # LIBS= # LIBS=-lnsl -lsocket LIBS=-lgmp RM=rm -f all: dhid genkeys dhid: conf.o network.o main.o $(CC) $(LFLAGS) -o dhid conf.o network.o main.o $(LIBS) genkeys: genkeys.c $(CC) $(CFLAGS) $(LFLAGS) -o genkeys genkeys.c $(LIBS) main.o: dhid.h main.c $(CC) $(CFLAGS) -c main.c network.o: dhid.h network.c $(CC) $(CFLAGS) -c network.c conf.o: dhid.h conf.c $(CC) $(CFLAGS) -c conf.c clean: $(RM) *.core genkeys core dhid *.o ./dhid-5.5/README000644 000764 000764 00000021205 11015264761 013243 0ustar00dhisdhis000000 000000 DHIS Daemon Client release 5.3 ============================== This distribution includes the source code for the DHIS daemon client dhid release 5.3. What is dhid ? -------------- dhid is the DHIS client daemon. After setting up with the DHIS provider, each machine may run a dhid daemon (in background) in order to update its dynamic IP address within the server. /etc/dhid.conf should be configured according to the provider's assigned parameters. Until release 4.0 DHIS was a system intended to provide dynamic DNS updates (on the server) only. In other words, the client daemon dhid would update its DNS entry within the server. As of R5 DHIS is no longer a Dynamic DNS protocol only. While service providers may in fact provide such a service with DHIS, other servers may also be offered based on the dynamic IP acquisiton. Once running, dhid sends echo request packets to the server and expects a reply. Once received, dhid tries to authenticate at the server either in password or qrc mode. From then on, and providing authentication was successful, the client waits and replies to queries originated at the server. If the server doesn't receive acknowledgments of these packets the host is marked offline. Likewise, if the client doesn't receive queries for a period of time the offline stage is restored. Therefore, the only thing a DHIS host needs is to run the dhid client. The server is able to determine when the host is online and the server tables are updated automatically. From R5 the DHIS client dhid no longer implements mail relaying functions or interactive mode. This release of the client however supports the following additional features: Multi-server support Multi-client update support Configurable refresh rates Possibility of running external commands when online/offline transitions occur. For an example of the possible options please see dhid.conf.sample Running dhid on a different incoming port ----------------------------------------- The incoming UDP port (for UDP messages from servers) is by default 58800. If you wish to run it on a different UDP port you may use the -p option. Example: dhid -p 59000 Will make dhid listen for UDP packets on port 59000 Running dhid under a user other than root ----------------------------------------- The DHIS daemon dhid can be executed by any user provided it has permissions to use (bind) the UDP port default 58800). AFAWK there is no real risk in running dhid as root, but if you're worried about security you may create a dhis user and run dhid as such. In this case make sure that the user under which dhid is being executed has permissions to read the /etc/dhid.conf file. Create a dedicated username (e.g. dhis) Make sure the user running dhid has access to dhid.conf (in the dhis user example) chown dhis /etc/dhid.conf Execute it under that user In startup script su -c dhis /somewhere/dhid If you want a pid file with the process ID number to be written, also make sure that either the user has permissions to write under /var/run or that you use the -P option described below to write somewhere where it has. Having dhid.conf on a different location ---------------------------------------- You may move dhid.conf anywhere and use the -f option to specify its location. Alternativelly you may update the DHID_CONF directive in dhid.h and recompile the client. e.g. dhid -f /usr/local/etc/dhid.conf Moving the PID file ------------------- The PID file location may also be specified on the command line using the -P option. Example: dhid -P /var/run/dhid.pid Logging ------- The DHIS client dhid does not send any output to stdout. Instead it uses syslog() to report messages. Error messages are logged under LOG_ERR and informational messages under LOG_INFO. Asynchronous Offline Packets ---------------------------- It is possible to instruct the IS to mark the host Offline at once. This procedure is performed automatically when the timeout is reached and no acknowledgements are received by the server. However, you may wish to speed up the offline process by including the offline request in his system's disconnection script. The command: kill -USR2 `cat /var/run/dhid.pid` issues an Offline packet request. Please note that this kill must be included in the script that is called prior to disconnection, not in the one that is executed once disconnection has happened. Also, you may wish to add a sleep of 1 second to allow the offline packet to get through. Multi-Server and Multi-Client support: -------------------------------------- The present client supports: 1) Multi-client updates on a single independent server 2) Multi-client updates on multiple independent servers 3) Single client updates on one of multi redundant servers 4) Or any combination of the above With option 1) it is possible to update multiple records (with multiple ids and keys) on a same server address/port. With option 2) it is possible to update multiple clients (with multiple ids and keys) on multiple server addresses/ports. With option 3) a same client (id and keys) is sent to a list of redundant servers. The client will pick up (for the session) the first replying server and will use it for futher communication. With this option it is possible to use the dhid client in a redundant / load sharing DHIS service provided that the DHIS service provider itself has servers in redundant mode. For more information on the usage of these options please see the example configuration file dhid.conf.sample Note for Multiserver/client: ---------------------------- Since R5 this client supports multiple server/clients. In the present release issuing an offline request with USR2 brings all records in dhid.conf to offline mode. Likewise when a connection is present all records in dhid.conf are automatically brought online. Firewalls: ---------- If you intend to run dhid behind a firewall make sure to allow both incoming and outgoing UDP packets to the configured server(s). The port is 58800 by default or other if specified in dhid.conf and/or with the -p option. Remember that this only changes the incoming port. The server port (to which the client sends packets) is defined at the service provider and cannot be changed by the client. Naturally don't be alarmed if you see incoming UDP packets arriving at your machine when running the dhid client. NAT Systems ----------- If your host is residing behind a NAT/PAT device (Network Address Translation / Port Translation) such as a Wireless LAN / ADSL router, a bit of additional configuration is needed. Outbound packets are automatically translated and thus require no action. I.E. the dhid client sends packets to the server's port 58800 and the NAT router translates the inside address to the outside address (possibly dynamically assigned by your ADSL or Cable ISP). Inbound packets however will arrive at the router and not at the machine running dhid. Therefore you need to configure a redirect rule at the NAT device mapping UDP packets targeted at the DHIS port to the private IP address of the machine running dhid. The following diagram illustrates an example scenario of this: -------- ADSL Router --------- Internet --- DHIS Server <10.0.0.1/24> <10.0.0.254/24> <212.1.1.1> 1) Client sends UDP packet from 10.0.0.1 to 212.1.1.1:58000 2) The router translates the source of the packet to the dynamic IP (NAT) 3) The server replies to the dynamic IP on port 58800 4) >>> The router must redirect (DMZ, etc ...) UDP packets to port 58800 to the inside address 10.0.0.1 Please note: In this case, the IP address considered and marked online by the DHIS server is the dynamic IP address, not the internal IP address. Hence if you wish to run a web server for example, on the same or a different machine inside your network, you need to redirect TCP port 80 as well to the web server. Services -------- Examples of services that DHIS may provide: Dynamic IP DNS Dynamic IP mail relaying and delivery Dynamic IP Tunnel establishment Dynamic IP ACL control Further Information ------------------- For further information concerning the dhid daemon, the DHIS server, for bug reporting or making suggestions please see our web site at www.dhis.org for contact information. We have removed references to email addresses from this distribution due to the excessive amounts of SPAM we were receiving on the support mailboxes. ./dhid-5.5/dhid.h000644 000764 000764 00000010730 11015277356 013451 0ustar00dhisdhis000000 000000 /*- * Copyright (c) 1998-2008 DHIS, Dynamic Host Information System * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef QRC #include #endif /* Define statements */ #define POLL_STAGE 1 #define AUTH_STAGE 2 #define ON_STAGE 3 #define DHIS_VERSION 55 /* DHIS Version */ #define MAX_HOSTNAME 64 #define MAX_PASS 16 /* Characters in password */ /* Message opcodes */ #define ECHO_REQ 0x00000511 #define ECHO_ACK 0x00000512 #define AUTH_REQ 0x00000521 #define AUTH_DENY 0x00000522 #define AUTH_ACK 0x00000526 /* 526 is 523 with return address for */ /* for versions >= 5.1 */ #define AUTH_SX 0x00000524 #define AUTH_SY 0x00000525 #define CHECK_REQ 0x00000541 #define CHECK_ACK 0x00000542 #define OFFLINE_REQ 0x00000551 #define DHID_CONF "/etc/dhid.conf" #define DHID_PID "/var/run/dhid.pid" #define DEF_ISPORT 58800 #define FAIL_ALLOW 3 #define POLL_FREQ 60 #define APASS 1 #define AQRC 2 /* Configuration section */ struct ser_t { char hostname[MAX_HOSTNAME]; int addr; int port; struct ser_t *next; }; struct conf_t { int id; /* HostID */ char pass[MAX_PASS]; /* Password */ int atype; struct ser_t *servers; struct ser_t *cserver; int refresh; int sid; int laddr; #ifdef QRC mpz_t authp; mpz_t authq; #endif int stage; int timeout; char on_cmd[256]; char on_cmdp[256]; char off_cmd[256]; char off_cmdp[256]; struct conf_t *next; }; char *line_entry(int,char *); char *line_ptr(int,char *); char *dot_entry(int,char *); void off_nl(char *); void strtolower(char *); void free_conf(void); void read_conf(char *); /* network section */ #define MAX_MSG 256 typedef struct { int opcode; int serial; int version; int rport; int hostid; } header_t; typedef struct { header_t hdr; char buff[MAX_MSG-sizeof(header_t)]; } msg_t; typedef struct { header_t hdr; } echo_req_t; typedef struct { header_t hdr; int oserial; } echo_ack_t; typedef struct { header_t hdr; char pass[16]; int refresh; } auth_req_t; typedef struct { header_t hdr; } auth_deny_t; typedef struct { header_t hdr; int sid; int raddr;} auth_ack_t; typedef struct { header_t hdr; char x[200]; } auth_sendx_t; typedef struct { header_t hdr; char y[200]; } auth_sendy_t; typedef struct { header_t hdr; int next_check; } check_req_t; typedef struct { header_t hdr; int sid; } check_ack_t; typedef struct { header_t hdr; int sid; } offline_req_t; int msg_size_by_opcode(int); void swap_int(int *); void swap_msg(int *,int); int little_endian(void); void convert_message(msg_t *,int); int get_serial(void); int net_init(int); int net_close(void); int net_check_message(void); int net_read_message(msg_t *,int *); int net_write_message(msg_t *,int,int); #ifdef QRC void qrc_random(mpz_t,int); void qrc_genkey(mpz_t); void qrc_genx(mpz_t,mpz_t); void qrc_geny(mpz_t,mpz_t,mpz_t); void qrc_sqrty(mpz_t,mpz_t,mpz_t); void qrc_crt(mpz_t,mpz_t,mpz_t,mpz_t,mpz_t); void qrc_fill_str(mpz_t,char *,int); #endif