home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
PC World 2000 September
/
PCWorld_2000-09_cd.bin
/
Komunik
/
sambar
/
_setup.1
/
dyndns.c
< prev
next >
Wrap
C/C++ Source or Header
|
2000-03-15
|
12KB
|
511 lines
/*
** DYNDNS
**
** HTTP Wrapper for the dyndns.org registration utility
**
** Confidential Property of Tod Sambar
** (c) Copyright Tod Sambar 2000
** All rights reserved.
**
**
** Public Functions:
**
** dyndns_init
** dyndns_ras
**
**
** History:
** Chg# Date Description Resp
** ---- ------- ------------------------------------------------------- ----
** 28FEB00 Created sambar
** 08FEB00 RAS callback added (untested!) sambar
*/
#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
#include <winsock.h>
#include <errno.h>
#include <dyndns.h>
/*
** Local configuration variables
*/
static SA_CHAR *service = "members.dyndns.org";
static SA_INT registered = 0;
static SA_INT wildcard_flag = 0;
static SA_INT backmx_flag = 0;
static SA_INT static_flag = 0;
static SA_CHAR mxname[256];
static SA_CHAR hostname[256];
static SA_CHAR username[256];
static SA_CHAR password[256];
/*
** Local Prototypes
*/
SA_RETCODE dyndns__load(SA_CTX *ctx, SA_VOID *argp,
SA_CHAR *name, SA_CHAR *value);
static SA_RETCODE dyndns__connect(SA_CTX *sactx, SA_CHAR *host,
SA_INT port, SOCKET *sockp);
static SA_RETCODE dyndns__disconnect(SA_CTX *sactx, SOCKET sock);
static SA_RETCODE dyndns__register(SA_CTX *sactx, SOCKET sock,
SA_CHAR *msg, SA_INT msglen);
static SA_RETCODE dyndns__auth(SA_CHAR *username, SA_CHAR *password,
SA_CHAR *auth);
/*
** DYNDNS_INIT
**
** Notify dyndns.org that the server is available.
**
** Note: The INIT and EXIT callbacks should be used if the server
** has a static IP address.
**
** Parameters:
** sactx Sambar Server context
**
** Returns:
** SA_SUCCEED | SA_FAIL
**
** Important! Use bin/serverd for debug information to ensure
** dyndns is working properly when initially configuring.
*/
SA_RETCODE SA_PUBLIC
dyndns_init(sactx)
SA_CTX *sactx;
{
SA_INT len;
SA_INT msglen;
SOCKET sock;
SA_CHAR ip[64];
SA_CHAR msg[2048];
SA_CHAR auth[256];
/*
** Register with the DYNDNS server (only if dyndns.ini is found/loaded).
*/
hostname[0] = '\0';
username[0] = '\0';
password[0] = '\0';
/*
** Load the dyndns configuration entries.
*/
if (sa_props_load(sactx, "dyndns.ini", "dyndns", NULL,
(SA_PROPFUNC)dyndns__load) != SA_SUCCEED)
{
sa_log(sactx, "DYNDNS no [init] configuration (dyndns.ini)...");
return (SA_SUCCEED);
}
/*
** Get the IP Address of this server.
*/
len = 0;
(SA_VOID)sa_ctx_props(sactx, SA_GET, SA_CTXPROP_SERVERIP,
(SA_BYTE *)ip, 60, &len);
ip[len] = '\0';
if (dyndns__connect(sactx, service, 80, &sock) != SA_SUCCEED)
{
sa_log(sactx, "DYNDNS registration failed");
return (SA_SUCCEED);
}
sprintf(msg,
"GET /nic/%sdns?action=edit&started=1&hostname=YES&host_id=%s&myip=%s",
static_flag ? "stat" : "dyn", hostname, ip);
msglen = strlen(msg);
if (wildcard_flag)
{
strcpy(&msg[msglen], "&wildcard=ON");
msglen += strlen(&msg[msglen]);
}
if (mxname[0] != '\0')
{
sprintf(&msg[msglen], "&mx=%s%s",
mxname, (backmx_flag ? "&backmx=YES" : ""));
msglen += strlen(&msg[msglen]);
}
strcpy(&msg[msglen], " HTTP/1.1\r\n");
msglen += strlen(&msg[msglen]);
(void)dyndns__auth(username, password, auth);
sprintf(&msg[msglen], "Host: %s\r\nAuthorization: Basic %s\r\n",
service, auth);
msglen += strlen(&msg[msglen]);
strcpy(&msg[msglen], "Content-Type: application/x-www-form-urlencoded\r\n");
msglen += strlen(&msg[msglen]);
strcpy(&msg[msglen], "Connection: close\r\n");
msglen += strlen(&msg[msglen]);
strcpy(&msg[msglen], "User-Agent: Sambar/4.3\r\n\r\n");
msglen += strlen(&msg[msglen]);
if (dyndns__register(sactx, sock, msg, msglen) != SA_SUCCEED)
{
sa_log(sactx, "DYNDNS registration request failed");
(void)dyndns__disconnect(sactx, sock);
return (SA_SUCCEED);
}
registered = 1;
(void)dyndns__disconnect(sactx, sock);
sa_log(sactx, "DYNDNS registration complete");
return (SA_SUCCEED);
}
/*
** DYNDNS_RAS
**
** Called when the RAS connection is established or disconnected.
** Perform the appropriate dyndns.org registration.
**
** Parameters:
** sactx Sambar Server context
** ip Active IP address.
** previp Previous IP address.
** connected RAS connected or disconnected.
**
** Returns:
** SA_SUCCEED | SA_FAIL
**
** Important! To prevent abuse, only re-register if the ip and previp
** are different.
*/
SA_VOID SA_PUBLIC
dndns_ras(sactx, ip, previp, connected)
SA_CTX *sactx;
SA_CHAR *ip;
SA_CHAR *previp;
SA_BOOL connected;
{
SA_INT msglen;
SOCKET sock;
SA_CHAR msg[2048];
SA_CHAR auth[256];
if (!connected)
return;
/*
** If the IP address has not changed, don't re-register
*/
if (strcmp(ip, previp) == 0)
return;
/*
** Load the dyndns configuration entries.
*/
if (sa_props_load(sactx, "dyndns.ini", "dyndns", NULL,
(SA_PROPFUNC)dyndns__load) != SA_SUCCEED)
{
sa_log(sactx, "DYNDNS-RAS no [init] configuration (dyndns.ini)...");
return;
}
/*
** Re-register with dyndns.org with the new IP address (if changed)
** as the modem is connected/disconnected rather than server
** start/stop.
*/
if (dyndns__connect(sactx, service, 80, &sock) != SA_SUCCEED)
{
sa_log(sactx, "DYNDNS-RAS registration failed");
return;
}
sprintf(msg,
"GET /nic/%sdns?action=edit&started=1&hostname=YES&host_id=%s&myip=%s",
static_flag ? "stat" : "dyn", hostname, ip);
msglen = strlen(msg);
if (wildcard_flag)
{
strcpy(&msg[msglen], "&wildcard=ON");
msglen += strlen(&msg[msglen]);
}
if (mxname[0] != '\0')
{
sprintf(&msg[msglen], "&mx=%s%s",
mxname, (backmx_flag ? "&backmx=YES" : ""));
msglen += strlen(&msg[msglen]);
}
strcpy(&msg[msglen], " HTTP/1.1\r\n");
msglen += strlen(&msg[msglen]);
(void)dyndns__auth(username, password, auth);
sprintf(&msg[msglen], "Host: %s\r\nAuthorization: Basic %s\r\n",
service, auth);
msglen += strlen(&msg[msglen]);
strcpy(&msg[msglen], "Content-Type: application/x-www-form-urlencoded\r\n");
msglen += strlen(&msg[msglen]);
strcpy(&msg[msglen], "Connection: close\r\n");
msglen += strlen(&msg[msglen]);
strcpy(&msg[msglen], "User-Agent: Sambar/4.3\r\n\r\n");
msglen += strlen(&msg[msglen]);
if (dyndns__register(sactx, sock, msg, msglen) != SA_SUCCEED)
{
sa_log(sactx, "DYNDNS-RAS registration request failed");
(void)dyndns__disconnect(sactx, sock);
return;
}
(void)dyndns__disconnect(sactx, sock);
sprintf(msg, "DYNDNS-RAS re-registration complete: %s", ip);
sa_log(sactx, msg);
return;
}
/*
** DYNDNS__LOAD
**
** Load a single dyndns configuration entry.
**
** Parameters:
** sactx Sambar Server context
** argp unused.
** name Left hand argument.
** value Right hand argument.
**
** Returns:
** SA_SUCCEED | SA_FAIL
*/
SA_RETCODE
dyndns__load(sactx, argp, name, value)
SA_CTX *sactx;
SA_VOID *argp;
SA_CHAR *name;
SA_CHAR *value;
{
if (strlen(value) > 255)
return (SA_FAIL);
if (stricmp(name, "wildcard") == 0)
{
if ((stricmp(value, "on") == 0) || (stricmp(value, "yes") == 0))
wildcard_flag = 1;
}
else if (stricmp(name, "backmx") == 0)
{
if ((stricmp(value, "on") == 0) || (stricmp(value, "yes") == 0))
backmx_flag = 1;
}
else if (stricmp(name, "static") == 0)
{
if ((stricmp(value, "on") == 0) || (stricmp(value, "yes") == 0))
static_flag = 1;
}
else if (stricmp(name, "mx") == 0)
{
strcpy(mxname, value);
}
else if (stricmp(name, "hostname") == 0)
{
strcpy(hostname, value);
}
else if (stricmp(name, "username") == 0)
{
strcpy(username, value);
}
else if (stricmp(name, "password") == 0)
{
strcpy(password, value);
}
return (SA_SUCCEED);
}
static SA_RETCODE
dyndns__connect(sactx, host, port, sockp)
SA_CTX *sactx;
SA_CHAR *host;
SA_INT port;
SOCKET *sockp;
{
int timeo;
SOCKET sock;
struct hostent *hent;
struct sockaddr_in sin;
/*
** Initialization
*/
memset((void *)&sin, 0, sizeof(sin));
/* Get the dyndns server address for the connect */
hent = gethostbyname(host);
if (hent == NULL)
{
sa_log(sactx, "DYNDNS unable to lookup host name");
return (SA_FAIL);
}
/* Create a socket */
sock = socket(hent->h_addrtype, SOCK_STREAM, 0);
if (sock == INVALID_SOCKET)
{
sa_log(sactx, "DYNDNS socket creation failed");
return (SA_FAIL);
}
/* Connect to the WHOIS server */
sin.sin_family = AF_INET;
sin.sin_port = htons((u_short)port);
memcpy(&sin.sin_addr, hent->h_addr, hent->h_length);
/* Now, connect to that WHOIS server */
if (connect(sock, (struct sockaddr *)&sin, sizeof(sin)) < 0)
{
closesocket(sock);
sa_log(sactx, "DYNDNS unable to connect to service");
return (SA_FAIL);
}
/* Set the socket timeout to 30 seconds */
timeo = 30000;
(void)setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, (const char *)&timeo,
sizeof(int));
*sockp = sock;
return (SA_SUCCEED);
}
static SA_RETCODE
dyndns__disconnect(sactx, sock)
SA_CTX *sactx;
SOCKET sock;
{
closesocket(sock);
return (SA_SUCCEED);
}
static SA_RETCODE
dyndns__register(sactx, sock, msg, msglen)
SA_CTX *sactx;
SOCKET sock;
SA_CHAR *msg;
SA_INT msglen;
{
SA_INT len;
SA_INT buflen;
SA_BOOL finished;
SA_CHAR buffer[1024];
if (send(sock, msg, msglen, 0) != msglen)
{
sa_log(sactx, "DYNDNS send of registration data failed.");
return (SA_FAIL);
}
/* Receive the response. */
len = 0;
finished = 0;
while (!finished)
{
buflen = recv(sock, &buffer[len], 1000 - len, 0);
if ((buflen < 0) && (errno == EINTR))
continue;
if (buflen == SOCKET_ERROR)
{
sa_log(sactx, "DYNDNS receive of registration request failed.");
return (SA_FAIL);
}
if (buflen > 0)
{
len += buflen;
if (len + buflen >= 1000)
finished = 1;
}
else
{
finished = 1;
}
}
buffer[len] = '\0';
if (len == 0)
{
sa_log(sactx, "DYNDNS no response received in 60 seconds");
return (SA_FAIL);
}
if (strstr(buffer, "blocked due to abuse"))
sa_log(sactx, "DYNDNS account blocked due to abuse.");
/*
** FIX THIS sambar - should check for 200 header message response.
*/
fprintf(stderr, "%s\n", buffer);
return (SA_SUCCEED);
}
static SA_RETCODE
dyndns__auth(username, password, auth)
SA_CHAR *username;
SA_CHAR *password;
SA_CHAR *auth;
{
static unsigned char alpha[] =
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
unsigned int bits;
int i;
int j;
int authlen;
int buflen;
char buffer[256];
sprintf(buffer, "%s:%s", username, password);
buflen = strlen(buffer);
i = 0;
authlen = 0;
while (i < buflen)
{
if (i && i % 54 == 0)
auth[authlen++] = '\n';
bits = buffer[i++];
for (j = 0; j < 2; j++)
{
bits <<= 8;
if (i < buflen)
bits += buffer[i++];
}
auth[authlen++] = alpha[bits >> 18];
auth[authlen++] = alpha[(bits >> 12) & 0x3f];
auth[authlen++] = alpha[(bits >> 6) & 0x3f];
auth[authlen++] = alpha[bits & 0x3f];
}
switch (buflen % 3)
{
case 1:
auth[authlen - 2] = '=';
case 2:
auth[authlen - 1] = '=';
break;
}
auth[authlen] = '\0';
return (SA_SUCCEED);
}