home *** CD-ROM | disk | FTP | other *** search
/ PC World 2000 September / PCWorld_2000-09_cd.bin / Komunik / sambar / _setup.1 / dyndns.c < prev    next >
C/C++ Source or Header  |  2000-03-15  |  12KB  |  511 lines

  1. /*
  2. ** DYNDNS
  3. **
  4. **      HTTP Wrapper for the dyndns.org registration utility
  5. **
  6. **        Confidential Property of Tod Sambar
  7. **        (c) Copyright Tod Sambar 2000
  8. **        All rights reserved.
  9. **
  10. **
  11. ** Public Functions:
  12. **
  13. **        dyndns_init
  14. **        dyndns_ras
  15. **
  16. **
  17. ** History:
  18. ** Chg#    Date    Description                                                Resp
  19. ** ----    -------    -------------------------------------------------------    ----
  20. **         28FEB00    Created                                                    sambar
  21. **         08FEB00    RAS callback added (untested!)                            sambar
  22. */
  23.  
  24. #include <windows.h>
  25. #include <stdio.h>
  26. #include <stdlib.h>
  27. #include <winsock.h>
  28. #include <errno.h>
  29. #include <dyndns.h>
  30.  
  31. /*
  32. ** Local configuration variables
  33. */
  34. static SA_CHAR    *service = "members.dyndns.org";
  35.  
  36. static SA_INT    registered = 0;
  37. static SA_INT    wildcard_flag = 0;
  38. static SA_INT    backmx_flag = 0;
  39. static SA_INT     static_flag = 0;
  40.  
  41. static SA_CHAR    mxname[256];
  42. static SA_CHAR    hostname[256];
  43. static SA_CHAR    username[256];
  44. static SA_CHAR    password[256];
  45.  
  46. /*
  47. ** Local Prototypes
  48. */
  49. SA_RETCODE                dyndns__load(SA_CTX *ctx, SA_VOID *argp, 
  50.                             SA_CHAR *name, SA_CHAR *value);
  51. static SA_RETCODE         dyndns__connect(SA_CTX *sactx, SA_CHAR *host, 
  52.                             SA_INT port, SOCKET *sockp);
  53. static SA_RETCODE         dyndns__disconnect(SA_CTX *sactx, SOCKET sock);
  54. static SA_RETCODE         dyndns__register(SA_CTX *sactx, SOCKET sock, 
  55.                             SA_CHAR *msg, SA_INT msglen);
  56. static SA_RETCODE         dyndns__auth(SA_CHAR *username, SA_CHAR *password, 
  57.                             SA_CHAR *auth);
  58.  
  59. /*
  60. **  DYNDNS_INIT
  61. **
  62. **    Notify dyndns.org that the server is available.
  63. **
  64. **    Note:  The INIT and EXIT callbacks should be used if the server
  65. **    has a static IP address.
  66. **
  67. **  Parameters:
  68. **    sactx        Sambar Server context
  69. **
  70. **  Returns:
  71. **    SA_SUCCEED | SA_FAIL
  72. **
  73. **    Important!    Use bin/serverd for debug information to ensure
  74. **    dyndns is working properly when initially configuring.
  75. */
  76. SA_RETCODE SA_PUBLIC
  77. dyndns_init(sactx)
  78. SA_CTX        *sactx;
  79. {
  80.     SA_INT        len;
  81.     SA_INT        msglen;
  82.     SOCKET        sock;
  83.     SA_CHAR        ip[64];
  84.     SA_CHAR        msg[2048];
  85.     SA_CHAR        auth[256];
  86.  
  87.     /*
  88.     ** Register with the DYNDNS server (only if dyndns.ini is found/loaded).
  89.     */
  90.     hostname[0] = '\0';
  91.     username[0] = '\0';
  92.     password[0] = '\0';
  93.  
  94.     /* 
  95.     ** Load the dyndns configuration entries.
  96.     */
  97.     if (sa_props_load(sactx, "dyndns.ini", "dyndns", NULL, 
  98.         (SA_PROPFUNC)dyndns__load) != SA_SUCCEED)
  99.     {
  100.         sa_log(sactx, "DYNDNS no [init] configuration (dyndns.ini)...");
  101.         return (SA_SUCCEED);
  102.     }
  103.  
  104.     /*
  105.     ** Get the IP Address of this server.
  106.     */
  107.     len = 0;
  108.     (SA_VOID)sa_ctx_props(sactx, SA_GET, SA_CTXPROP_SERVERIP, 
  109.         (SA_BYTE *)ip, 60, &len);
  110.     ip[len] = '\0';
  111.  
  112.     if (dyndns__connect(sactx, service, 80, &sock) != SA_SUCCEED)
  113.     {
  114.         sa_log(sactx, "DYNDNS registration failed");
  115.         return (SA_SUCCEED);
  116.     }
  117.  
  118.     sprintf(msg, 
  119.         "GET /nic/%sdns?action=edit&started=1&hostname=YES&host_id=%s&myip=%s",
  120.         static_flag ? "stat" : "dyn", hostname, ip);
  121.  
  122.     msglen = strlen(msg);
  123.  
  124.     if (wildcard_flag)     
  125.     {
  126.         strcpy(&msg[msglen], "&wildcard=ON");
  127.         msglen += strlen(&msg[msglen]);
  128.     }
  129.  
  130.     if (mxname[0] != '\0') 
  131.     {
  132.         sprintf(&msg[msglen], "&mx=%s%s", 
  133.             mxname, (backmx_flag ? "&backmx=YES" : ""));
  134.         msglen += strlen(&msg[msglen]);
  135.     }
  136.   
  137.     strcpy(&msg[msglen], " HTTP/1.1\r\n");
  138.     msglen += strlen(&msg[msglen]);
  139.  
  140.     (void)dyndns__auth(username, password, auth);
  141.     sprintf(&msg[msglen], "Host: %s\r\nAuthorization: Basic %s\r\n", 
  142.         service, auth);
  143.     msglen += strlen(&msg[msglen]);
  144.     
  145.     strcpy(&msg[msglen], "Content-Type: application/x-www-form-urlencoded\r\n");
  146.     msglen += strlen(&msg[msglen]);
  147.     strcpy(&msg[msglen], "Connection: close\r\n");
  148.     msglen += strlen(&msg[msglen]);
  149.     strcpy(&msg[msglen], "User-Agent: Sambar/4.3\r\n\r\n");
  150.     msglen += strlen(&msg[msglen]);
  151.     
  152.     if (dyndns__register(sactx, sock, msg, msglen) != SA_SUCCEED)
  153.     {
  154.         sa_log(sactx, "DYNDNS registration request failed");
  155.         (void)dyndns__disconnect(sactx, sock);
  156.         return (SA_SUCCEED);
  157.     }
  158.     
  159.     registered = 1;
  160.     (void)dyndns__disconnect(sactx, sock);
  161.     sa_log(sactx, "DYNDNS registration complete");
  162.  
  163.     return (SA_SUCCEED);
  164. }
  165.  
  166. /*
  167. **  DYNDNS_RAS
  168. **
  169. **    Called when the RAS connection is established or disconnected.
  170. **    Perform the appropriate dyndns.org registration. 
  171. **
  172. **  Parameters:
  173. **    sactx        Sambar Server context
  174. **    ip            Active IP address.
  175. **    previp        Previous IP address.
  176. **    connected    RAS connected or disconnected.
  177. **
  178. **  Returns:
  179. **    SA_SUCCEED | SA_FAIL
  180. **
  181. **    Important!    To prevent abuse, only re-register if the ip and previp
  182. **                are different.
  183. */
  184. SA_VOID SA_PUBLIC
  185. dndns_ras(sactx, ip, previp, connected)
  186. SA_CTX        *sactx;
  187. SA_CHAR        *ip;
  188. SA_CHAR        *previp;
  189. SA_BOOL        connected;
  190. {
  191.     SA_INT        msglen;
  192.     SOCKET        sock;
  193.     SA_CHAR        msg[2048];
  194.     SA_CHAR        auth[256];
  195.  
  196.     if (!connected)
  197.         return;
  198.  
  199.     /*
  200.     ** If the IP address has not changed, don't re-register
  201.     */
  202.     if (strcmp(ip, previp) == 0)
  203.         return;
  204.  
  205.     /* 
  206.     ** Load the dyndns configuration entries.
  207.     */
  208.     if (sa_props_load(sactx, "dyndns.ini", "dyndns", NULL, 
  209.         (SA_PROPFUNC)dyndns__load) != SA_SUCCEED)
  210.     {
  211.         sa_log(sactx, "DYNDNS-RAS no [init] configuration (dyndns.ini)...");
  212.         return;
  213.     }
  214.  
  215.     /*
  216.     ** Re-register with dyndns.org with the new IP address (if changed) 
  217.     ** as the modem is connected/disconnected rather than server
  218.     ** start/stop.
  219.     */
  220.     if (dyndns__connect(sactx, service, 80, &sock) != SA_SUCCEED)
  221.     {
  222.         sa_log(sactx, "DYNDNS-RAS registration failed");
  223.         return;
  224.     }
  225.  
  226.     sprintf(msg, 
  227.         "GET /nic/%sdns?action=edit&started=1&hostname=YES&host_id=%s&myip=%s",
  228.         static_flag ? "stat" : "dyn", hostname, ip);
  229.  
  230.     msglen = strlen(msg);
  231.  
  232.     if (wildcard_flag)     
  233.     {
  234.         strcpy(&msg[msglen], "&wildcard=ON");
  235.         msglen += strlen(&msg[msglen]);
  236.     }
  237.  
  238.     if (mxname[0] != '\0') 
  239.     {
  240.         sprintf(&msg[msglen], "&mx=%s%s", 
  241.             mxname, (backmx_flag ? "&backmx=YES" : ""));
  242.         msglen += strlen(&msg[msglen]);
  243.     }
  244.   
  245.     strcpy(&msg[msglen], " HTTP/1.1\r\n");
  246.     msglen += strlen(&msg[msglen]);
  247.  
  248.     (void)dyndns__auth(username, password, auth);
  249.     sprintf(&msg[msglen], "Host: %s\r\nAuthorization: Basic %s\r\n", 
  250.         service, auth);
  251.     msglen += strlen(&msg[msglen]);
  252.     
  253.     strcpy(&msg[msglen], "Content-Type: application/x-www-form-urlencoded\r\n");
  254.     msglen += strlen(&msg[msglen]);
  255.     strcpy(&msg[msglen], "Connection: close\r\n");
  256.     msglen += strlen(&msg[msglen]);
  257.     strcpy(&msg[msglen], "User-Agent: Sambar/4.3\r\n\r\n");
  258.     msglen += strlen(&msg[msglen]);
  259.     
  260.     if (dyndns__register(sactx, sock, msg, msglen) != SA_SUCCEED)
  261.     {
  262.         sa_log(sactx, "DYNDNS-RAS registration request failed");
  263.         (void)dyndns__disconnect(sactx, sock);
  264.         return;
  265.     }
  266.     
  267.     (void)dyndns__disconnect(sactx, sock);
  268.     sprintf(msg, "DYNDNS-RAS re-registration complete: %s", ip);
  269.     sa_log(sactx, msg);
  270.  
  271.     return;
  272. }
  273.  
  274. /*
  275. **  DYNDNS__LOAD
  276. **
  277. **    Load a single dyndns configuration entry.
  278. **
  279. **  Parameters:
  280. **    sactx        Sambar Server context
  281. **    argp        unused.
  282. **    name        Left hand argument.
  283. **    value        Right hand argument.
  284. **
  285. **  Returns:
  286. **    SA_SUCCEED | SA_FAIL
  287. */
  288. SA_RETCODE
  289. dyndns__load(sactx, argp, name, value)
  290. SA_CTX        *sactx;
  291. SA_VOID        *argp;
  292. SA_CHAR        *name;
  293. SA_CHAR        *value;
  294. {
  295.     if (strlen(value) > 255)
  296.         return (SA_FAIL);
  297.  
  298.     if (stricmp(name, "wildcard") == 0)
  299.     {
  300.         if ((stricmp(value, "on") == 0) || (stricmp(value, "yes") == 0))
  301.             wildcard_flag = 1;
  302.     }
  303.     else if (stricmp(name, "backmx") == 0)
  304.     {
  305.         if ((stricmp(value, "on") == 0) || (stricmp(value, "yes") == 0))
  306.             backmx_flag = 1;
  307.     }
  308.     else if (stricmp(name, "static") == 0)
  309.     {
  310.         if ((stricmp(value, "on") == 0) || (stricmp(value, "yes") == 0))
  311.             static_flag = 1;
  312.     }
  313.     else if (stricmp(name, "mx") == 0)
  314.     {
  315.         strcpy(mxname, value);
  316.     }
  317.     else if (stricmp(name, "hostname") == 0)
  318.     {
  319.         strcpy(hostname, value);
  320.     }
  321.     else if (stricmp(name, "username") == 0)
  322.     {
  323.         strcpy(username, value);
  324.     }
  325.     else if (stricmp(name, "password") == 0)
  326.     {
  327.         strcpy(password, value);
  328.     }
  329.  
  330.     return (SA_SUCCEED);
  331. }
  332.  
  333. static SA_RETCODE 
  334. dyndns__connect(sactx, host, port, sockp)
  335. SA_CTX        *sactx;
  336. SA_CHAR        *host; 
  337. SA_INT        port;
  338. SOCKET         *sockp;
  339. {
  340.     int                    timeo;
  341.     SOCKET                sock;
  342.     struct hostent        *hent;
  343.     struct sockaddr_in    sin;
  344.  
  345.     /*
  346.     ** Initialization
  347.     */
  348.     memset((void *)&sin, 0, sizeof(sin));
  349.  
  350.     /* Get the dyndns server address for the connect                    */
  351.     hent = gethostbyname(host);
  352.     if (hent == NULL)
  353.     {
  354.         sa_log(sactx, "DYNDNS unable to lookup host name");
  355.         return (SA_FAIL);
  356.     }
  357.  
  358.     /* Create a socket                                                     */
  359.     sock = socket(hent->h_addrtype, SOCK_STREAM, 0);
  360.     if (sock == INVALID_SOCKET)
  361.     {
  362.         sa_log(sactx, "DYNDNS socket creation failed");
  363.         return (SA_FAIL);
  364.     }
  365.  
  366.     /* Connect to the WHOIS server                                        */
  367.     sin.sin_family = AF_INET;
  368.     sin.sin_port = htons((u_short)port);
  369.     memcpy(&sin.sin_addr, hent->h_addr, hent->h_length);
  370.  
  371.     /* Now, connect to that WHOIS server                                */
  372.     if (connect(sock, (struct sockaddr *)&sin, sizeof(sin)) < 0) 
  373.     {
  374.         closesocket(sock);
  375.         sa_log(sactx, "DYNDNS unable to connect to service");
  376.         return (SA_FAIL);
  377.     }
  378.  
  379.     /* Set the socket timeout to 30 seconds                                */
  380.     timeo = 30000;
  381.     (void)setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, (const char *)&timeo,
  382.         sizeof(int));
  383.  
  384.     *sockp = sock;
  385.     return (SA_SUCCEED);
  386. }
  387.  
  388. static SA_RETCODE 
  389. dyndns__disconnect(sactx, sock)
  390. SA_CTX        *sactx;
  391. SOCKET         sock;
  392. {
  393.     closesocket(sock);
  394.     return (SA_SUCCEED);
  395. }
  396.  
  397. static SA_RETCODE 
  398. dyndns__register(sactx, sock, msg, msglen)
  399. SA_CTX        *sactx;
  400. SOCKET         sock;
  401. SA_CHAR        *msg; 
  402. SA_INT        msglen;
  403. {
  404.     SA_INT        len;
  405.     SA_INT        buflen;
  406.     SA_BOOL        finished;
  407.     SA_CHAR        buffer[1024];
  408.  
  409.     if (send(sock, msg, msglen, 0) != msglen)
  410.     {
  411.         sa_log(sactx, "DYNDNS send of registration data failed.");
  412.         return (SA_FAIL);
  413.     }
  414.  
  415.     /* Receive the response.                                            */
  416.     len = 0;
  417.     finished = 0;
  418.     while (!finished)
  419.     {
  420.         buflen = recv(sock, &buffer[len], 1000 - len, 0);
  421.         if ((buflen < 0) && (errno == EINTR))
  422.             continue;
  423.  
  424.         if (buflen == SOCKET_ERROR)
  425.         {
  426.             sa_log(sactx, "DYNDNS receive of registration request failed.");
  427.             return (SA_FAIL);
  428.         }
  429.  
  430.         if (buflen > 0)
  431.         {
  432.             len += buflen;
  433.             if (len + buflen >= 1000)
  434.                 finished = 1;
  435.         }
  436.         else
  437.         {
  438.             finished = 1;
  439.         }
  440.     }
  441.  
  442.     buffer[len] = '\0';
  443.     if (len == 0)
  444.     {
  445.         sa_log(sactx, "DYNDNS no response received in 60 seconds");
  446.         return (SA_FAIL);
  447.     }
  448.  
  449.     if (strstr(buffer, "blocked due to abuse")) 
  450.         sa_log(sactx, "DYNDNS account blocked due to abuse.");
  451.  
  452.     /*
  453.     ** FIX THIS sambar - should check for 200 header message response.
  454.     */
  455.     fprintf(stderr, "%s\n", buffer);
  456.    
  457.     return (SA_SUCCEED);
  458. }
  459.  
  460. static SA_RETCODE
  461. dyndns__auth(username, password, auth)
  462. SA_CHAR        *username;
  463. SA_CHAR        *password;
  464. SA_CHAR        *auth;
  465. {
  466.     static unsigned char alpha[] =
  467.         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
  468.     unsigned int bits;
  469.     int         i;
  470.     int         j;
  471.     int         authlen;
  472.     int         buflen;
  473.     char        buffer[256];
  474.  
  475.     sprintf(buffer, "%s:%s", username, password);
  476.     buflen = strlen(buffer);
  477.  
  478.     i = 0;
  479.     authlen = 0;
  480.     while (i < buflen) 
  481.     {
  482.         if (i && i % 54 == 0)
  483.             auth[authlen++] = '\n';
  484.  
  485.         bits = buffer[i++];
  486.         for (j = 0; j < 2; j++) 
  487.         {
  488.             bits <<= 8;
  489.             if (i < buflen)
  490.                 bits += buffer[i++];
  491.         }
  492.  
  493.         auth[authlen++] = alpha[bits >> 18];
  494.         auth[authlen++] = alpha[(bits >> 12) & 0x3f];
  495.         auth[authlen++] = alpha[(bits >> 6) & 0x3f];
  496.         auth[authlen++] = alpha[bits & 0x3f];
  497.     }
  498.  
  499.     switch (buflen % 3) 
  500.     {
  501.     case 1:
  502.         auth[authlen - 2] = '=';
  503.     case 2:
  504.         auth[authlen - 1] = '=';
  505.         break;
  506.     }
  507.     auth[authlen] = '\0';
  508.  
  509.     return (SA_SUCCEED);
  510. }
  511.