home *** CD-ROM | disk | FTP | other *** search
/ PC World 2002 May / PCWorld_2002-05_cd.bin / Komunik / sambar / sambar51p.exe / samples / source / dyndns.c < prev    next >
Encoding:
C/C++ Source or Header  |  2001-12-09  |  11.5 KB  |  516 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_log2(sactx, SA_LOG_WARN, 
  101.             "DYNDNS no [init] configuration (dyndns.ini)...");
  102.         return (SA_SUCCEED);
  103.     }
  104.  
  105.     /*
  106.     ** Get the IP Address of this server.
  107.     */
  108.     len = 0;
  109.     (SA_VOID)sa_ctx_props(sactx, SA_GET, SA_CTXPROP_SERVERIP, 
  110.         (SA_BYTE *)ip, 60, &len);
  111.     ip[len] = '\0';
  112.  
  113.     if (dyndns__connect(sactx, service, 80, &sock) != SA_SUCCEED)
  114.     {
  115.         sa_log2(sactx, SA_LOG_ERROR, "DYNDNS registration failed");
  116.         return (SA_SUCCEED);
  117.     }
  118.  
  119.     sprintf(msg, 
  120.         "GET /nic/%sdns?action=edit&started=1&hostname=YES&host_id=%s&myip=%s",
  121.         static_flag ? "stat" : "dyn", hostname, ip);
  122.  
  123.     msglen = strlen(msg);
  124.  
  125.     if (wildcard_flag)     
  126.     {
  127.         strcpy(&msg[msglen], "&wildcard=ON");
  128.         msglen += strlen(&msg[msglen]);
  129.     }
  130.  
  131.     if (mxname[0] != '\0') 
  132.     {
  133.         sprintf(&msg[msglen], "&mx=%s%s", 
  134.             mxname, (backmx_flag ? "&backmx=YES" : ""));
  135.         msglen += strlen(&msg[msglen]);
  136.     }
  137.   
  138.     strcpy(&msg[msglen], " HTTP/1.1\r\n");
  139.     msglen += strlen(&msg[msglen]);
  140.  
  141.     (void)dyndns__auth(username, password, auth);
  142.     sprintf(&msg[msglen], "Host: %s\r\nAuthorization: Basic %s\r\n", 
  143.         service, auth);
  144.     msglen += strlen(&msg[msglen]);
  145.     
  146.     strcpy(&msg[msglen], "Content-Type: application/x-www-form-urlencoded\r\n");
  147.     msglen += strlen(&msg[msglen]);
  148.     strcpy(&msg[msglen], "Connection: close\r\n");
  149.     msglen += strlen(&msg[msglen]);
  150.     strcpy(&msg[msglen], "User-Agent: Sambar/4.3\r\n\r\n");
  151.     msglen += strlen(&msg[msglen]);
  152.     
  153.     if (dyndns__register(sactx, sock, msg, msglen) != SA_SUCCEED)
  154.     {
  155.         sa_log2(sactx, SA_LOG_ERROR, "DYNDNS registration request failed");
  156.         (void)dyndns__disconnect(sactx, sock);
  157.         return (SA_SUCCEED);
  158.     }
  159.     
  160.     registered = 1;
  161.     (void)dyndns__disconnect(sactx, sock);
  162.     sa_log2(sactx, SA_LOG_INFO, "DYNDNS registration complete");
  163.  
  164.     return (SA_SUCCEED);
  165. }
  166.  
  167. /*
  168. **  DYNDNS_RAS
  169. **
  170. **    Called when the RAS connection is established or disconnected.
  171. **    Perform the appropriate dyndns.org registration. 
  172. **
  173. **  Parameters:
  174. **    sactx        Sambar Server context
  175. **    ip            Active IP address.
  176. **    previp        Previous IP address.
  177. **    connected    RAS connected or disconnected.
  178. **
  179. **  Returns:
  180. **    SA_SUCCEED | SA_FAIL
  181. **
  182. **    Important!    To prevent abuse, only re-register if the ip and previp
  183. **                are different.
  184. */
  185. SA_VOID SA_PUBLIC
  186. dyndns_ras(sactx, ip, previp, connected)
  187. SA_CTX        *sactx;
  188. SA_CHAR        *ip;
  189. SA_CHAR        *previp;
  190. SA_BOOL        connected;
  191. {
  192.     SA_INT        msglen;
  193.     SOCKET        sock;
  194.     SA_CHAR        msg[2048];
  195.     SA_CHAR        auth[256];
  196.  
  197.     if (!connected)
  198.         return;
  199.  
  200.     /*
  201.     ** If the IP address has not changed, don't re-register
  202.     */
  203.     if (strcmp(ip, previp) == 0)
  204.         return;
  205.  
  206.     /* 
  207.     ** Load the dyndns configuration entries.
  208.     */
  209.     if (sa_props_load(sactx, "dyndns.ini", "dyndns", NULL, 
  210.         (SA_PROPFUNC)dyndns__load) != SA_SUCCEED)
  211.     {
  212.         sa_log2(sactx, SA_LOG_WARN, 
  213.             "DYNDNS-RAS no [init] configuration (dyndns.ini)...");
  214.         return;
  215.     }
  216.  
  217.     /*
  218.     ** Re-register with dyndns.org with the new IP address (if changed) 
  219.     ** as the modem is connected/disconnected rather than server
  220.     ** start/stop.
  221.     */
  222.     if (dyndns__connect(sactx, service, 80, &sock) != SA_SUCCEED)
  223.     {
  224.         sa_log2(sactx, SA_LOG_WARN, "DYNDNS-RAS registration failed");
  225.         return;
  226.     }
  227.  
  228.     sprintf(msg, 
  229.         "GET /nic/%sdns?action=edit&started=1&hostname=YES&host_id=%s&myip=%s",
  230.         static_flag ? "stat" : "dyn", hostname, ip);
  231.  
  232.     msglen = strlen(msg);
  233.  
  234.     if (wildcard_flag)     
  235.     {
  236.         strcpy(&msg[msglen], "&wildcard=ON");
  237.         msglen += strlen(&msg[msglen]);
  238.     }
  239.  
  240.     if (mxname[0] != '\0') 
  241.     {
  242.         sprintf(&msg[msglen], "&mx=%s%s", 
  243.             mxname, (backmx_flag ? "&backmx=YES" : ""));
  244.         msglen += strlen(&msg[msglen]);
  245.     }
  246.   
  247.     strcpy(&msg[msglen], " HTTP/1.1\r\n");
  248.     msglen += strlen(&msg[msglen]);
  249.  
  250.     (void)dyndns__auth(username, password, auth);
  251.     sprintf(&msg[msglen], "Host: %s\r\nAuthorization: Basic %s\r\n", 
  252.         service, auth);
  253.     msglen += strlen(&msg[msglen]);
  254.     
  255.     strcpy(&msg[msglen], "Content-Type: application/x-www-form-urlencoded\r\n");
  256.     msglen += strlen(&msg[msglen]);
  257.     strcpy(&msg[msglen], "Connection: close\r\n");
  258.     msglen += strlen(&msg[msglen]);
  259.     strcpy(&msg[msglen], "User-Agent: Sambar/4.3\r\n\r\n");
  260.     msglen += strlen(&msg[msglen]);
  261.     
  262.     if (dyndns__register(sactx, sock, msg, msglen) != SA_SUCCEED)
  263.     {
  264.         sa_log2(sactx, SA_LOG_WARN, "DYNDNS-RAS registration request failed");
  265.         (void)dyndns__disconnect(sactx, sock);
  266.         return;
  267.     }
  268.     
  269.     (void)dyndns__disconnect(sactx, sock);
  270.     sprintf(msg, "DYNDNS-RAS re-registration complete: %s", ip);
  271.     sa_log2(sactx, SA_LOG_INFO, msg);
  272.  
  273.     return;
  274. }
  275.  
  276. /*
  277. **  DYNDNS__LOAD
  278. **
  279. **    Load a single dyndns configuration entry.
  280. **
  281. **  Parameters:
  282. **    sactx        Sambar Server context
  283. **    argp        unused.
  284. **    name        Left hand argument.
  285. **    value        Right hand argument.
  286. **
  287. **  Returns:
  288. **    SA_SUCCEED | SA_FAIL
  289. */
  290. SA_RETCODE
  291. dyndns__load(sactx, argp, name, value)
  292. SA_CTX        *sactx;
  293. SA_VOID        *argp;
  294. SA_CHAR        *name;
  295. SA_CHAR        *value;
  296. {
  297.     if (strlen(value) > 255)
  298.         return (SA_FAIL);
  299.  
  300.     if (stricmp(name, "wildcard") == 0)
  301.     {
  302.         if ((stricmp(value, "on") == 0) || (stricmp(value, "yes") == 0))
  303.             wildcard_flag = 1;
  304.     }
  305.     else if (stricmp(name, "backmx") == 0)
  306.     {
  307.         if ((stricmp(value, "on") == 0) || (stricmp(value, "yes") == 0))
  308.             backmx_flag = 1;
  309.     }
  310.     else if (stricmp(name, "static") == 0)
  311.     {
  312.         if ((stricmp(value, "on") == 0) || (stricmp(value, "yes") == 0))
  313.             static_flag = 1;
  314.     }
  315.     else if (stricmp(name, "mx") == 0)
  316.     {
  317.         strcpy(mxname, value);
  318.     }
  319.     else if (stricmp(name, "hostname") == 0)
  320.     {
  321.         strcpy(hostname, value);
  322.     }
  323.     else if (stricmp(name, "username") == 0)
  324.     {
  325.         strcpy(username, value);
  326.     }
  327.     else if (stricmp(name, "password") == 0)
  328.     {
  329.         strcpy(password, value);
  330.     }
  331.  
  332.     return (SA_SUCCEED);
  333. }
  334.  
  335. static SA_RETCODE 
  336. dyndns__connect(sactx, host, port, sockp)
  337. SA_CTX        *sactx;
  338. SA_CHAR        *host; 
  339. SA_INT        port;
  340. SOCKET         *sockp;
  341. {
  342.     int                    timeo;
  343.     SOCKET                sock;
  344.     struct hostent        *hent;
  345.     struct sockaddr_in    sin;
  346.  
  347.     /*
  348.     ** Initialization
  349.     */
  350.     memset((void *)&sin, 0, sizeof(sin));
  351.  
  352.     /* Get the dyndns server address for the connect                    */
  353.     hent = gethostbyname(host);
  354.     if (hent == NULL)
  355.     {
  356.         sa_log2(sactx, SA_LOG_ERROR, "DYNDNS unable to lookup host name");
  357.         return (SA_FAIL);
  358.     }
  359.  
  360.     /* Create a socket                                                     */
  361.     sock = socket(hent->h_addrtype, SOCK_STREAM, 0);
  362.     if (sock == INVALID_SOCKET)
  363.     {
  364.         sa_log2(sactx, SA_LOG_ERROR, "DYNDNS socket creation failed");
  365.         return (SA_FAIL);
  366.     }
  367.  
  368.     /* Connect to the WHOIS server                                        */
  369.     sin.sin_family = AF_INET;
  370.     sin.sin_port = htons((u_short)port);
  371.     memcpy(&sin.sin_addr, hent->h_addr, hent->h_length);
  372.  
  373.     /* Now, connect to that WHOIS server                                */
  374.     if (connect(sock, (struct sockaddr *)&sin, sizeof(sin)) < 0) 
  375.     {
  376.         closesocket(sock);
  377.         sa_log2(sactx, SA_LOG_ERROR, "DYNDNS unable to connect to service");
  378.         return (SA_FAIL);
  379.     }
  380.  
  381.     /* Set the socket timeout to 30 seconds                                */
  382.     timeo = 30000;
  383.     (void)setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, (const char *)&timeo,
  384.         sizeof(int));
  385.  
  386.     *sockp = sock;
  387.     return (SA_SUCCEED);
  388. }
  389.  
  390. static SA_RETCODE 
  391. dyndns__disconnect(sactx, sock)
  392. SA_CTX        *sactx;
  393. SOCKET         sock;
  394. {
  395.     closesocket(sock);
  396.     return (SA_SUCCEED);
  397. }
  398.  
  399. static SA_RETCODE 
  400. dyndns__register(sactx, sock, msg, msglen)
  401. SA_CTX        *sactx;
  402. SOCKET         sock;
  403. SA_CHAR        *msg; 
  404. SA_INT        msglen;
  405. {
  406.     SA_INT        len;
  407.     SA_INT        buflen;
  408.     SA_BOOL        finished;
  409.     SA_CHAR        buffer[1024];
  410.  
  411.     if (send(sock, msg, msglen, 0) != msglen)
  412.     {
  413.         sa_log2(sactx, SA_LOG_ERROR, 
  414.             "DYNDNS send of registration data failed.");
  415.         return (SA_FAIL);
  416.     }
  417.  
  418.     /* Receive the response.                                            */
  419.     len = 0;
  420.     finished = 0;
  421.     while (!finished)
  422.     {
  423.         buflen = recv(sock, &buffer[len], 1000 - len, 0);
  424.         if ((buflen < 0) && (errno == EINTR))
  425.             continue;
  426.  
  427.         if (buflen == SOCKET_ERROR)
  428.         {
  429.             sa_log2(sactx, SA_LOG_ERROR, 
  430.                 "DYNDNS receive of registration request failed.");
  431.             return (SA_FAIL);
  432.         }
  433.  
  434.         if (buflen > 0)
  435.         {
  436.             len += buflen;
  437.             if (len + buflen >= 1000)
  438.                 finished = 1;
  439.         }
  440.         else
  441.         {
  442.             finished = 1;
  443.         }
  444.     }
  445.  
  446.     buffer[len] = '\0';
  447.     if (len == 0)
  448.     {
  449.         sa_log2(sactx, SA_LOG_ERROR, 
  450.             "DYNDNS no response received in 60 seconds");
  451.         return (SA_FAIL);
  452.     }
  453.  
  454.     if (strstr(buffer, "blocked due to abuse")) 
  455.         sa_log2(sactx, SA_LOG_WARN, "DYNDNS account blocked due to abuse.");
  456.  
  457.     /*
  458.     ** FIX THIS sambar - should check for 200 header message response.
  459.     */
  460.     fprintf(stderr, "%s\n", buffer);
  461.    
  462.     return (SA_SUCCEED);
  463. }
  464.  
  465. static SA_RETCODE
  466. dyndns__auth(username, password, auth)
  467. SA_CHAR        *username;
  468. SA_CHAR        *password;
  469. SA_CHAR        *auth;
  470. {
  471.     static unsigned char alpha[] =
  472.         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
  473.     unsigned int bits;
  474.     int         i;
  475.     int         j;
  476.     int         authlen;
  477.     int         buflen;
  478.     char        buffer[256];
  479.  
  480.     sprintf(buffer, "%s:%s", username, password);
  481.     buflen = strlen(buffer);
  482.  
  483.     i = 0;
  484.     authlen = 0;
  485.     while (i < buflen) 
  486.     {
  487.         if (i && i % 54 == 0)
  488.             auth[authlen++] = '\n';
  489.  
  490.         bits = buffer[i++];
  491.         for (j = 0; j < 2; j++) 
  492.         {
  493.             bits <<= 8;
  494.             if (i < buflen)
  495.                 bits += buffer[i++];
  496.         }
  497.  
  498.         auth[authlen++] = alpha[bits >> 18];
  499.         auth[authlen++] = alpha[(bits >> 12) & 0x3f];
  500.         auth[authlen++] = alpha[(bits >> 6) & 0x3f];
  501.         auth[authlen++] = alpha[bits & 0x3f];
  502.     }
  503.  
  504.     switch (buflen % 3) 
  505.     {
  506.     case 1:
  507.         auth[authlen - 2] = '=';
  508.     case 2:
  509.         auth[authlen - 1] = '=';
  510.         break;
  511.     }
  512.     auth[authlen] = '\0';
  513.  
  514.     return (SA_SUCCEED);
  515. }
  516.