/*************************************************************************** * Copyright (C) 2005 Meni Livne * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ***************************************************************************/ #include #include #include #ifdef WIN32 #include #define snprintf _snprintf #define ssize_t int #else #include #include #include #endif #include "phish.h" #include "phish_util_net.h" #define BUF_SIZE 1024 typedef struct { struct hostent *ent; char *buf; } phish_util_hostent_t; static void freeHostent(phish_util_hostent_t *h) { #ifndef WIN32 free(h->ent); #endif free(h->buf); free(h); } static phish_util_hostent_t *phish_getHostByName(const char *name) { #ifndef WIN32 int result, err; #endif phish_util_hostent_t *h = malloc(sizeof(phish_util_hostent_t)); if (h == NULL) { return NULL; } h->ent = NULL; h->buf = NULL; #if defined(WIN32) || defined(FreeBSD) h->ent = gethostbyname(name); if (h->ent == NULL) { freeHostent(h); return NULL; } return h; #else h->ent = malloc(sizeof(struct hostent)); if (h->ent == NULL) { freeHostent(h); return NULL; } h->buf = malloc(BUF_SIZE); if (h->buf == NULL) { freeHostent(h); return NULL; } result = gethostbyname_r(name, h->ent, h->buf, BUF_SIZE, &h->ent, &err); if (result != 0 || h->ent == NULL) { freeHostent(h); return NULL; } return h; #endif } phish_result_t phish_util_hostToIP(const char *host, char **ip) { phish_result_t r = PHISH_SUCCESS; phish_util_hostent_t *h; h = phish_getHostByName(host); if (h == NULL || h->ent == NULL) { return PHISH_ERR_RESOLVE; } *ip = strdup(inet_ntoa(*(struct in_addr*)h->ent->h_addr)); if (*ip == NULL) { r = PHISH_ERR_MEMORY; } freeHostent(h); return r; } phish_result_t phish_util_tcpConnect(int sock, const char *server, int port) { struct sockaddr_in server_addr; phish_util_hostent_t *server_host; server_host = phish_getHostByName(server); if (server_host == NULL) { return PHISH_ERR_RESOLVE; } server_addr.sin_family = AF_INET; server_addr.sin_port = htons(port); memcpy(&server_addr.sin_addr, server_host->ent->h_addr_list[0], server_host->ent->h_length); memset(server_addr.sin_zero, 0, 8); freeHostent(server_host); /* connect to server */ if (connect(sock, (struct sockaddr *)&server_addr, sizeof(server_addr)) == -1) { return PHISH_ERR_TCP_CONNECT; } return PHISH_SUCCESS; } phish_result_t phish_util_sockReadLine(int sock, char *line, size_t line_length) { char last_char_read; char *pos = line; size_t length_remain = line_length; ssize_t bytes_read; do { bytes_read = recv(sock, pos, 1, 0); last_char_read = *pos; pos++; length_remain--; } while (bytes_read > 0 && length_remain > 1 && last_char_read != '\r' && last_char_read != '\n'); if (bytes_read == -1) return PHISH_ERR_SOCK_READ; *pos = '\0'; if (last_char_read == '\r') { /* remove trailing carriage return and read new line character */ char dummy; *(--pos) = '\0'; bytes_read = recv(sock, &dummy, 1, 0); if (bytes_read == -1) return PHISH_ERR_SOCK_READ; } return PHISH_SUCCESS; } static phish_result_t sockWrite(int sock, const char *line) { ssize_t bytes_written = 1; char *pos = (char *)line; size_t length_remain = strlen(line); while (bytes_written > 0 && length_remain > 0) { bytes_written = send(sock, line, length_remain, 0); pos += bytes_written; length_remain -= bytes_written; } if (bytes_written == -1) return PHISH_ERR_SOCK_WRITE; return PHISH_SUCCESS; } phish_result_t phish_util_sockWriteLine(int sock, const char *line) { const char *crlf = "\r\n"; if (sockWrite(sock, line) != PHISH_SUCCESS) { return PHISH_ERR_SOCK_WRITE; } if (sockWrite(sock, crlf) != PHISH_SUCCESS) { return PHISH_ERR_SOCK_WRITE; } return PHISH_SUCCESS; } static phish_result_t phish_util_sendHttpGetHeader(int sock, const char *field, const char *content) { int line_len; char *line; line_len = strlen(field) + 2 + strlen(content) + 1; line = malloc(line_len); if (line == NULL) return PHISH_ERR_MEMORY; snprintf(line, line_len, "%s: %s", field, content); if (phish_util_sockWriteLine(sock, line) != PHISH_SUCCESS) { return PHISH_ERR_SOCK_WRITE; } free(line); return PHISH_SUCCESS; } phish_result_t phish_util_httpGet(int sock, const char *path, const char *version, const char *host, const char *user_agent, const char *referrer, const char *if_none_match, int keep_alive) { char *line; size_t line_len; /* send GET line */ line_len = 4 + strlen(path) + 6 + strlen(version) + 1; line = malloc(line_len); if (line == NULL) return PHISH_ERR_MEMORY; snprintf(line, line_len, "GET %s HTTP/%s", path, version); if (phish_util_sockWriteLine(sock, line) != PHISH_SUCCESS) { return PHISH_ERR_SOCK_WRITE; } free(line); if (host != NULL) { if (phish_util_sendHttpGetHeader(sock, "Host", host) != PHISH_SUCCESS) { return PHISH_ERR_SOCK_WRITE; } } if (user_agent != NULL) { if (phish_util_sendHttpGetHeader(sock, "User-Agent", user_agent) != PHISH_SUCCESS) { return PHISH_ERR_SOCK_WRITE; } } if (referrer != NULL) { if (phish_util_sendHttpGetHeader(sock, "Referer", referrer) != PHISH_SUCCESS) { return PHISH_ERR_SOCK_WRITE; } } if (if_none_match != NULL) { if (phish_util_sendHttpGetHeader(sock, "If-None-Match", if_none_match) != PHISH_SUCCESS) { return PHISH_ERR_SOCK_WRITE; } } if (keep_alive) { if (phish_util_sendHttpGetHeader(sock, "Connection", "Keep-Alive") != PHISH_SUCCESS) { return PHISH_ERR_SOCK_WRITE; } } else { if (phish_util_sendHttpGetHeader(sock, "Connection", "close") != PHISH_SUCCESS) { return PHISH_ERR_SOCK_WRITE; } } if (phish_util_sockWriteLine(sock, "") != PHISH_SUCCESS) { return PHISH_ERR_SOCK_WRITE; } return PHISH_SUCCESS; } phish_result_t phish_util_parseHTTPReply(int sock, phish_util_http_headers_t *result) { char buf[BUF_SIZE]; int dummy; int i = 0; /* initialise result structure */ result->status_code = -1; result->content_length = -1; result->etag = NULL; /* read status line, e.g. "200 OK" */ if (phish_util_sockReadLine(sock, buf, BUF_SIZE) != PHISH_SUCCESS) { return PHISH_ERR_SOCK_READ; } if (sscanf(buf, "HTTP/%d.%d %d", &dummy, &dummy, &result->status_code) != 3) return PHISH_ERR_HTTP_BAD_HEADER; if (phish_util_sockReadLine(sock, buf, BUF_SIZE) != PHISH_SUCCESS) { return PHISH_ERR_SOCK_READ; } /* read rest of headers in reply */ while (strcmp(buf, "") != 0) { char *field, *content; i = 0; /* extract field name and field content from reply line */ while (buf[i] != '\0' && buf[i] != ':') i++; if (buf[i] == '\0') return PHISH_ERR_HTTP_BAD_HEADER; field = malloc(i + 1); if (field == NULL) return PHISH_ERR_MEMORY; strncpy(field, buf, i); field[i++] = '\0'; while (buf[i] != '\0' && buf[i] == ' ') i++; if (buf[i] == '\0') { free(field); return PHISH_ERR_HTTP_BAD_HEADER; } content = malloc(strlen(buf + i) + 1); if (content == NULL) { free(field); return PHISH_ERR_MEMORY; } strncpy(content, buf + i, strlen(buf + i)); content[strlen(buf + i)] = '\0'; if (strcmp(field, "Content-Length") == 0) { result->content_length = atoi(content); } else if (strcmp(field, "ETag") == 0) { result->etag = malloc(strlen(content) + 1); if (!result->etag) { return PHISH_ERR_MEMORY; } strcpy(result->etag, content); } free(field); free(content); if (phish_util_sockReadLine(sock, buf, BUF_SIZE) != PHISH_SUCCESS) { return PHISH_ERR_SOCK_READ; } } while (strcmp(buf, "") != 0); return PHISH_SUCCESS; }