Skip to content

Instantly share code, notes, and snippets.

@joli80
Last active December 17, 2015 14:59
Show Gist options
  • Save joli80/4753e949b7db652b8741 to your computer and use it in GitHub Desktop.
Save joli80/4753e949b7db652b8741 to your computer and use it in GitHub Desktop.
Simple Linux DynDNS update client
// Based on http://coding.debuntu.org/c-linux-socket-programming-tcp-simple-http-client
#include <stdio.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <stdlib.h>
#include <netdb.h>
#include <string.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/select.h>
#include <sys/time.h>
#include <sys/un.h>
int create_tcp_socket();
char *get_ip(char *host);
char *build_get_query(char *host, char *page, char *auth);
void usage();
#define HOST ""
#define PAGE "/"
#define PORT 80
#define USERAGENT "Company - Device - 1.0"
int main(int argc, char **argv)
{
struct sockaddr_in *remote;
int sock;
int tmpres;
char *ip;
char *get;
char buf[BUFSIZ + 1];
char *host;
char *page;
char *auth;
if (argc == 1) {
usage();
exit(2);
}
host = argv[1];
if (argc > 2) {
page = argv[2];
}
else {
page = PAGE;
}
if (argc > 3) {
auth = argv[3];
}
sock = create_tcp_socket();
ip = get_ip(host);
fprintf(stderr, "IP is %s\n", ip);
remote = (struct sockaddr_in *)malloc(sizeof(struct sockaddr_in *));
remote->sin_family = AF_INET;
tmpres = inet_pton(AF_INET, ip, (void *)(&(remote->sin_addr.s_addr)));
if (tmpres < 0)
{
perror("Can't set remote->sin_addr.s_addr");
exit(1);
}
else if (tmpres == 0)
{
fprintf(stderr, "%s is not a valid IP address\n", ip);
exit(1);
}
remote->sin_port = htons(PORT);
if (connect(sock, (struct sockaddr *)remote, sizeof(struct sockaddr)) < 0) {
perror("Could not connect");
exit(1);
}
get = build_get_query(host, page, auth);
fprintf(stderr, "Query is:\n<<START>>\n%s<<END>>\n", get);
//Send the query to the server
int sent = 0;
while (sent < strlen(get))
{
tmpres = send(sock, get + sent, strlen(get) - sent, 0);
if (tmpres == -1) {
perror("Can't send query");
exit(1);
}
sent += tmpres;
}
//now it is time to receive the page
memset(buf, 0, sizeof(buf));
int htmlstart = 0;
char * htmlcontent;
while ((tmpres = recv(sock, buf, BUFSIZ, 0)) > 0) {
if (htmlstart == 0)
{
/* Under certain conditions this will not work.
* If the \r\n\r\n part is splitted into two messages
* it will fail to detect the beginning of HTML content
*/
htmlcontent = strstr(buf, "\r\n\r\n");
if (htmlcontent != NULL) {
htmlstart = 1;
htmlcontent += 4;
}
}
else {
htmlcontent = buf;
}
if (htmlstart) {
fprintf(stdout, htmlcontent);
}
memset(buf, 0, tmpres);
}
if (tmpres < 0)
{
perror("Error receiving data");
}
free(get);
free(remote);
free(ip);
close(sock);
return 0;
}
void usage()
{
fprintf(stderr, "USAGE: htmlget host [page]\n\
\thost: the website hostname. ex: coding.debuntu.org\n\
\tpage: the page to retrieve. ex: index.html, default: /\n");
}
int create_tcp_socket()
{
int sock;
if ((sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) {
perror("Can't create TCP socket");
exit(1);
}
return sock;
}
char *get_ip(char *host)
{
struct hostent *hent;
int iplen = 15; //XXX.XXX.XXX.XXX
char *ip = (char *)malloc(iplen + 1);
memset(ip, 0, iplen + 1);
if ((hent = gethostbyname(host)) == NULL)
{
herror("Can't get IP");
exit(1);
}
if (inet_ntop(AF_INET, (void *)hent->h_addr_list[0], ip, iplen) == NULL)
{
perror("Can't resolve host");
exit(1);
}
return ip;
}
char *build_get_query(char *host, char *page, char *auth)
{
char *query;
char *getpage = page;
char *tpl = "GET /%s HTTP/1.0\r\nHost: %s\r\nUser-Agent: %s\r\nAuthorization: Basic %s\r\n\r\n";
if (getpage[0] == '/') {
getpage = getpage + 1;
fprintf(stderr, "Removing leading \"/\", converting %s to %s\n", page, getpage);
}
// -5 is to consider the %s %s %s in tpl and the ending \0
query = (char *)malloc(strlen(host) + strlen(getpage) + strlen(USERAGENT) + strlen(tpl) - 5);
sprintf(query, tpl, getpage, host, USERAGENT, auth);
return query;
}
@joli80
Copy link
Author

joli80 commented Dec 17, 2015

USAGE: htmlget host page auth
host: the website hostname. ex: members.dyndns.org
page: the page to retrieve. ex: nic/update?hostname=myhost.dyndns.org
auth: base64 encode of username:password

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment