I am trying to make a c program to create port forwarding rule using libiptc.
static int insert_forward_rule(const char *table, const char *chain, unsigned int src, unsigned int dest, const char * ports, const char *target1, char * proto) {
struct xtc_handle *h;
struct ipt_entry *en = NULL;
struct ipt_entry * e;
struct ipt_entry_match * match_proto, * match_limit;
struct ipt_entry_target * target;
unsigned int size_ipt_entry, size_ipt_entry_match, size_ipt_entry_target, total_length;
size_ipt_entry = IPT_ALIGN(sizeof (struct ipt_entry));
size_ipt_entry_match = IPT_ALIGN(sizeof (struct ipt_entry_match)) + sizeof (struct ipt_tcp) + sizeof (int);
size_ipt_entry_target = IPT_ALIGN(sizeof (struct ipt_entry_target) + sizeof (IPTC_LABEL_ACCEPT));
total_length = 216; //size_ipt_entry + size_ipt_entry_match + size_ipt_entry_target + IPT_ALIGN(sizeof (struct ipt_natinfo)); //size_ipt_entry + 48 + 40
//printf("size of ipt ebtry=%u,match=%u,target=%u,total=%u\n", size_ipt_entry, size_ipt_entry_match, size_ipt_entry_target, total_length);
//memory allocation for all structs that represent the netfilter rule we want to insert
e = calloc(1, total_length);
if (e == NULL) {
printf("malloc failure");
exit(1);
}
int size = 160;
//offsets to the other bits:
//target struct begining
e->target_offset = size; //size_ipt_entry + size_ipt_entry_match; //+ size_ipt_tcp + size_rateinfo + size_physdevinfo;
//next "e" struct, end of the current one
e->next_offset = total_length;
e->nfcache = NFC_IP_DST_PT;
if (dest) {
e->ip.dst.s_addr = dest;
e->ip.dmsk.s_addr = 0xFFFFFFFF;
}
match_limit = (struct ipt_entry_match *) (e->elems); //+ match_proto->u.match_size
match_limit->u.user.match_size = size_ipt_entry_match; //size_ipt_entry_match*3; //+ size_rateinfo;
strncpy(match_limit->u.user.name, "tcp", sizeof (match_limit->u.user.name)); //set name of the module, we will use in this match
struct ipt_tcp *info = (struct ipt_tcp *) match_limit->data;
unsigned int i = 0;
if (strchr(ports, ':') != NULL) {
char aPort[2][10];
sscanf(ports, "%[^:], %[^:]", aPort[0], aPort[1]);
info->dpts[0] = atoi(aPort[0]);
info->dpts[1] = atoi(aPort[1]);
} else {
info->dpts[0] = info->dpts[1] = atoi(ports);
}
info->spts[0] = 0;
info->spts[1] = 0xFFFF;
e->ip.proto = IPPROTO_TCP;
printf("Target offset=%d,next offset=%d\n", e->target_offset, e->next_offset);
target = (struct ipt_entry_target *) ((void*) e + e->target_offset); // + size_ipt_entry_match); //+ size_ipt_tcp + size_rateinfo + size_physdevinfo
size = 56;
target->u.user.target_size = size_ipt_entry_target + IPT_ALIGN(sizeof (struct nf_nat_range)); // size_ipt_entry_target;
target->u.user.revision = 0;
strncpy(target->u.user.name, target1, sizeof (target->u.user.name));
struct ipt_natinfo *inf = (struct ipt_natinfo*) target->data;
struct nf_nat_range range;
memset(&range, 0, sizeof (range));
range.flags |= IP_NAT_RANGE_MAP_IPS;
range.min_ip = range.max_ip = src;
inf->mr.rangesize++;
inf->mr.range[inf->mr.rangesize] = range;
inf->t.u.target_size = XT_ALIGN(sizeof (*inf) + inf->mr.rangesize * sizeof (struct nf_nat_range));
printf("after s_addr\n\n");
//All the functions, mentioned below could be found in "Querying libiptc HOWTO" manual
h = iptc_init(table);
printf("h=%d\n", h);
if (!h) {
printf("Error initializing: %s\n", iptc_strerror(errno));
return 0;
}
printf("target_size=%d,match=%d,chain=%s,table=%s,target=%s\n", target->u.user.target_size, match_limit->u.user.match_size, chain, table, target1);
int x = iptc_append_entry(chain, e, h);
if (!x) {
printf("Error append_entry: %s\n", iptc_strerror(errno));
goto ERROR;
}
printf("%d,chain=%s,target=%s\n", target->u.user.target_size, chain, table);
int y = iptc_commit(h);
if (!y) {
printf("Error no=%d,commit: %s\n", errno, iptc_strerror(errno));
goto ERROR;
}
iptc_free(h);
if (e != NULL) {
free(e);
e = NULL;
}
return 1;
ERROR:
iptc_free(h);
if (e != NULL) {
free(e);
e = NULL;
}
return 0;
}
To call this function
inet_pton(AF_INET, "20.10.10.254", &a);
inet_pton(AF_INET, "20.10.10.100", &b);
insert_forward_rule("nat", "port_forward", b, a, "1111", "DNAT", "tcp");
Every time i run this code i am getting error as invalid arguments(code 22).If i change the position of rangesize to below iptc_init() then it gave an error code 94(socket operation on non-socket)
I tried struct nf_nat_range structure directly but then its not saving the destination ip in rules instead of that its showing random.
Rule which i want to make is
iptables -t nat -A port_forward -j DNAT -d 192.168.10.202 -p udp --dport 8080:8084 --to 20.10.10.112
what it is creating with structure nf_nat_range is
Chain port_forward (0 references)
pkts bytes target prot opt in out source destination
0 0 DNAT tcp -- * * 0.0.0.0/0 20.10.10.254 tcp dpt:1111 to: random
0 0 DNAT tcp -- * * 0.0.0.0/0 20.10.10.254 tcp dpt:1111 to: random
0 0 DNAT tcp -- * * 0.0.0.0/0 20.10.10.254 tcp dpt:1111 to: random
These are the functions which helped me to Add or Delete DNAT and SNAT rules using libiptc. I uploaded this to my GitHub account.
void iptc_add_rule(const char *table, const char *chain, const char *protocol, const char *iniface, const char *outiface, const char *src, const char *dest, const char *srcports, const char *destports, const char *target, const char *dnat_to, const int append) {
iptc_handle_t handle;
struct ipt_entry *chain_entry;
struct ipt_entry_match *entry_match = NULL;
struct ipt_entry_target *entry_target;
ipt_chainlabel labelit;
long match_size;
int result = 0;
chain_entry = (struct ipt_entry *) calloc(1, sizeof (*chain_entry));
if (src) {
chain_entry->ip.src.s_addr = inet_addr(src);
chain_entry->ip.smsk.s_addr = inet_addr("255.255.255.255");
}
if (dest) {
chain_entry->ip.dst.s_addr = inet_addr(dest);
chain_entry->ip.dmsk.s_addr = inet_addr("255.255.255.255");
}
if (iniface) strncpy(chain_entry->ip.iniface, iniface, IFNAMSIZ);
if (outiface) strncpy(chain_entry->ip.outiface, outiface, IFNAMSIZ);
if (strcmp(protocol, "TCP") == 0) {
chain_entry->ip.proto = IPPROTO_TCP;
entry_match = get_tcp_match(srcports, destports, &chain_entry->nfcache);
} else if (strcmp(protocol, "UDP") == 0) {
chain_entry->ip.proto = IPPROTO_UDP;
entry_match = get_udp_match(srcports, destports, &chain_entry->nfcache);
} else {
printf("Unsupported protocol: %s", protocol);
return;
}
if (strcmp(target, "") == 0
|| strcmp(target, IPTC_LABEL_ACCEPT) == 0
|| strcmp(target, IPTC_LABEL_DROP) == 0
|| strcmp(target, IPTC_LABEL_QUEUE) == 0
|| strcmp(target, IPTC_LABEL_RETURN) == 0) {
size_t size;
size = IPT_ALIGN(sizeof (struct ipt_entry_target)) + IPT_ALIGN(sizeof (int));
entry_target = (struct ipt_entry_target *) calloc(1, size);
entry_target->u.user.target_size = size;
strncpy(entry_target->u.user.name, target, IPT_FUNCTION_MAXNAMELEN);
} else if (strcmp(target, "DNAT") == 0) {
entry_target = get_dnat_target(dnat_to, &chain_entry->nfcache);
printf("dnat\n");
} else if (strcmp(target, "SNAT") == 0) {
entry_target = get_snat_target(dnat_to, &chain_entry->nfcache);
printf("snat\n");
}
if (entry_match)
match_size = entry_match->u.match_size;
else
match_size = 0;
struct ipt_entry *tmp_ipt = chain_entry;
chain_entry = (struct ipt_entry *) realloc(chain_entry, sizeof (*chain_entry) + match_size + entry_target->u.target_size);
if (chain_entry == NULL) {
free(tmp_ipt);
}
memcpy(chain_entry->elems + match_size, entry_target, entry_target->u.target_size);
chain_entry->target_offset = sizeof (*chain_entry) + match_size;
chain_entry->next_offset = sizeof (*chain_entry) + match_size + entry_target->u.target_size;
printf("target->offset=%d,next_offset=%d,target_size=%d\n", chain_entry->target_offset, chain_entry->next_offset, entry_target->u.user.target_size);
if (entry_match) {
memcpy(chain_entry->elems, entry_match, match_size);
printf("%d\n", __LINE__);
}
printf("%d\n", __LINE__);
handle = iptc_init(table);
if (!handle) {
printf("libiptc error: Can't initialize table %s, %s", table, iptc_strerror(errno));
free(chain_entry);
free(entry_target);
if (entry_match) free(entry_match);
return;
}
strncpy(labelit, chain, sizeof (ipt_chainlabel));
printf("%d\n", __LINE__);
result = iptc_is_chain(chain, handle);
if (!result) {
printf("libiptc error: Chain %s does not exist!", chain);
free(chain_entry);
free(entry_target);
if (entry_match) free(entry_match);
return;
}
printf("%d,labeit=%s\n", __LINE__, labelit);
if (append)
result = iptc_append_entry(labelit, chain_entry, handle);
else
result = iptc_insert_entry(labelit, chain_entry, 0, handle);
printf("%d\n", __LINE__);
if (!result) {
printf("libiptc error: Can't add, %s", iptc_strerror(errno));
free(chain_entry);
free(entry_target);
if (entry_match) free(entry_match);
return;
}
printf("%d\n", __LINE__);
result = iptc_commit(handle);
if (!result) {
printf("libiptc error: Commit error, %s", iptc_strerror(errno));
free(chain_entry);
free(entry_target);
if (entry_match) free(entry_match);
return;
} else
printf("added new rule to block successfully");
if (entry_match) free(entry_match);
free(entry_target);
free(chain_entry);
}
void iptc_delete_rule(const char *table, const char *chain, const char *protocol, const char *iniface, const char *outiface, const char *src, const char *dest, const char *srcports, const char *destports, const char *target, const char *dnat_to) {
iptc_handle_t handle;
const struct ipt_entry *e;
ipt_chainlabel labelit;
int i, result;
unsigned long int s_src, s_dest;
if (src) s_src = inet_addr(src);
if (dest) s_dest = inet_addr(dest);
handle = iptc_init(table);
if (!handle) {
printf("libiptc error: Can't initialize table %s, %s", table, iptc_strerror(errno));
return;
}
strncpy(labelit, chain, sizeof (ipt_chainlabel));
result = iptc_is_chain(chain, handle);
if (!result) {
printf("libiptc error: Chain %s does not exist!", chain);
return;
}
for (e = iptc_first_rule(chain, handle), i = 0; e; e = iptc_next_rule(e, handle), i++) {
if (src && e->ip.src.s_addr != s_src) continue;
else if (dest && e->ip.dst.s_addr != s_dest) continue;
else if (iniface && strcmp(e->ip.iniface, iniface) != 0) continue;
else if (outiface && strcmp(e->ip.outiface, outiface) != 0) continue;
else if (protocol && strcmp(protocol, "TCP") == 0 && e->ip.proto != IPPROTO_TCP) continue;
else if (protocol && strcmp(protocol, "UDP") == 0 && e->ip.proto != IPPROTO_UDP) continue;
else if ((srcports || destports) && IPT_MATCH_ITERATE_MY(e, matchcmp, srcports, destports) == 0) continue;
else if (target && strcmp(target, iptc_get_target(e, handle)) != 0) continue;
else if (dnat_to && strcmp(target, "DNAT") == 0) {
struct ipt_entry_target *t;
struct ip_nat_multi_range *mr;
struct ip_nat_range *r, range;
t = (struct ipt_entry_target *) (e + e->target_offset);
mr = (struct ip_nat_multi_range *) ((void *) &t->data);
if (mr->rangesize != 1) continue; // we have only single dnat_to target now
r = mr->range;
parse_range(dnat_to, &range);
if (r->flags == range.flags
&& r->min_ip == range.min_ip
&& r->max_ip == range.max_ip
&& r->min.all == range.min.all
&& r->max.all == range.max.all) {
break;
}
} else break;
}
if (!e) return;
result = iptc_delete_num_entry(chain, i, handle);
if (!result) {
printf("libiptc error: Delete error, %s", iptc_strerror(errno));
return;
}
result = iptc_commit(handle);
if (!result) {
printf("libiptc error: Commit error, %s", iptc_strerror(errno));
return;
} else
printf("deleted rule from block successfully");
}
int matchcmp(const struct ipt_entry_match *match, const char *srcports, const char *destports) {
u_int16_t temp[2];
if (strcmp(match->u.user.name, "tcp") == 0) {
struct ipt_tcp *tcpinfo = (struct ipt_tcp *) match->data;
if (srcports) {
parse_ports(srcports, temp);
if (temp[0] != tcpinfo->spts[0] || temp[1] != tcpinfo->spts[1]) return 0;
}
if (destports) {
parse_ports(destports, temp);
if (temp[0] != tcpinfo->dpts[0] || temp[1] != tcpinfo->dpts[1]) return 0;
}
return 1;
} else if (strcmp(match->u.user.name, "udp") == 0) {
struct ipt_udp *udpinfo = (struct ipt_udp *) match->data;
if (srcports) {
parse_ports(srcports, temp);
if (temp[0] != udpinfo->spts[0] || temp[1] != udpinfo->spts[1]) return 0;
}
if (destports) {
parse_ports(destports, temp);
if (temp[0] != udpinfo->dpts[0] || temp[1] != udpinfo->dpts[1]) return 0;
}
return 1;
} else return 0;
}
/* These functions are used to create structs */
struct ipt_entry_match *get_tcp_match(const char *sports, const char *dports, unsigned int *nfcache) {
struct ipt_entry_match *match;
struct ipt_tcp *tcpinfo;
size_t size;
size = IPT_ALIGN(sizeof (*match)) + IPT_ALIGN(sizeof (*tcpinfo));
match = (struct ipt_entry_match *) calloc(1, size);
match->u.match_size = size;
strncpy(match->u.user.name, "tcp", IPT_FUNCTION_MAXNAMELEN);
tcpinfo = (struct ipt_tcp *) match->data;
tcpinfo->spts[1] = tcpinfo->dpts[1] = 0xFFFF;
printf("sports=%s,dports=%s\n", sports, dports);
if (sports) {
*nfcache |= NFC_IP_SRC_PT;
parse_ports(sports, tcpinfo->spts);
printf("%d\n", __LINE__);
}
if (dports) {
*nfcache |= NFC_IP_DST_PT;
parse_ports(dports, tcpinfo->dpts);
printf("%d\n", __LINE__);
}
return match;
}
struct ipt_entry_match *get_udp_match(const char *sports, const char *dports, unsigned int *nfcache) {
struct ipt_entry_match *match;
struct ipt_udp *udpinfo;
size_t size;
size = IPT_ALIGN(sizeof (*match)) + IPT_ALIGN(sizeof (*udpinfo));
match = (struct ipt_entry_match *) calloc(1, size);
match->u.match_size = size;
strncpy(match->u.user.name, "udp", IPT_FUNCTION_MAXNAMELEN);
udpinfo = (struct ipt_udp *) match->data;
udpinfo->spts[1] = udpinfo->dpts[1] = 0xFFFF;
printf("sports=%s,dports=%s\n", sports, dports);
if (sports) {
*nfcache |= NFC_IP_SRC_PT;
parse_ports(sports, udpinfo->spts);
printf("%d\n", __LINE__);
}
if (dports) {
*nfcache |= NFC_IP_DST_PT;
parse_ports(dports, udpinfo->dpts);
printf("%d\n", __LINE__);
}
return match;
}
struct ipt_entry_target *get_dnat_target(const char *input, unsigned int *nfcache) {
struct ipt_entry_target *target;
struct ipt_natinfo *info;
struct ip_nat_range range;
char *buffer;
size_t size;
/* Can't cache this */
*nfcache |= NFC_UNKNOWN;
buffer = strdup(input);
size = IPT_ALIGN(sizeof (*target)) + IPT_ALIGN(sizeof (struct ip_nat_multi_range));
target = (struct ipt_entry_target *) calloc(1, size);
target->u.target_size = size;
strncpy(target->u.user.name, "DNAT", IPT_FUNCTION_MAXNAMELEN);
info = (struct ipt_natinfo *) target;
printf("buffer range=%s\n", buffer);
parse_range(buffer, &range);
target = &(append_range(info, &range)->t);
printf("range=%d\n", range.flags);
printf("%d\n", __LINE__);
free(buffer);
return target;
}
struct ipt_entry_target *get_snat_target(const char *input, unsigned int *nfcache) {
struct ipt_entry_target *target;
struct ipt_natinfo *info;
struct ip_nat_range range;
char *buffer;
size_t size;
/* Can't cache this */
*nfcache |= NFC_UNKNOWN;
buffer = strdup(input);
size = IPT_ALIGN(sizeof (*target)) + IPT_ALIGN(sizeof (struct ip_nat_multi_range));
target = (struct ipt_entry_target *) calloc(1, size);
target->u.target_size = size;
strncpy(target->u.user.name, "SNAT", IPT_FUNCTION_MAXNAMELEN);
info = (struct ipt_natinfo *) target;
printf("buffer range=%s\n", buffer);
parse_range(buffer, &range);
target = &(append_range(info, &range)->t);
printf("range=%d\n", range.flags);
printf("%d\n", __LINE__);
free(buffer);
return target;
}
/* Copied and modified from libipt_tcp.c and libipt_udp.c */
static u_int16_t parse_port(const char *port) {
unsigned int portnum;
if ((portnum = service_to_port(port)) != -1) {
return (u_int16_t) portnum;
} else {
return atoi(port);
}
}
static void parse_ports(const char *portstring, u_int16_t *ports) {
char *buffer;
char *cp;
buffer = strdup(portstring);
if ((cp = strchr(buffer, ':')) == NULL)
ports[0] = ports[1] = parse_port(buffer);
else {
*cp = '\0';
cp++;
ports[0] = buffer[0] ? parse_port(buffer) : 0;
ports[1] = cp[0] ? parse_port(cp) : 0xFFFF;
}
free(buffer);
}
static int service_to_port(const char *name) {
struct servent *service;
if ((service = getservbyname(name, "tcp")) != NULL)
return ntohs((unsigned short) service->s_port);
return -1;
}
/* Copied and modified from libipt_DNAT.c */
static void parse_range(const char *input, struct ip_nat_range *range) {
char *colon, *dash, *buffer;
in_addr_t ip;
buffer = strdup(input);
memset(range, 0, sizeof (*range));
colon = strchr(buffer, ':');
if (colon) {
int port;
range->flags |= IP_NAT_RANGE_PROTO_SPECIFIED;
port = atoi(colon + 1);
dash = strchr(colon, '-');
if (!dash) {
range->min.all
= range->max.all
= htons(port);
} else {
int maxport;
maxport = atoi(dash + 1);
range->min.all = htons(port);
range->max.all = htons(maxport);
}
/* Starts with a colon? No IP info...*/
if (colon == buffer) {
free(buffer);
return;
}
*colon = '\0';
}
range->flags |= IP_NAT_RANGE_MAP_IPS;
dash = strchr(buffer, '-');
if (colon && dash && dash > colon)
dash = NULL;
if (dash)
*dash = '\0';
ip = inet_addr(buffer);
range->min_ip = ip;
if (dash) {
ip = inet_addr(dash + 1);
range->max_ip = ip;
} else
range->max_ip = range->min_ip;
free(buffer);
return;
}
static struct ipt_natinfo *append_range(struct ipt_natinfo *info, const struct ip_nat_range *range) {
unsigned int size;
/* One ip_nat_range already included in ip_nat_multi_range */
size = IPT_ALIGN(sizeof (*info) + info->mr.rangesize * sizeof (*range));
info = (struct ipt_natinfo *) realloc(info, size);
info->t.u.target_size = size;
info->mr.range[info->mr.rangesize] = *range;
info->mr.rangesize++;
printf("range size=%d\n", info->mr.rangesize);
return info;
}
Related
I am trying to unzip data in ZLIB using the uncompress function. the data to be decompressed is in a Char vector. the library was downloaded from github for C language. code below:
//C
unsigned char out[20000], u_out[20000];
size_t size_out;
unsigned char* in = ""; //non inserisco i dati di partenza per privacy
int err, i;
long int ucompSize_out;
long int compSize_out;
size_out=sizeof(out);
//codifica in base45
err=base45_decode(out,&size_out,in,strlen(in));
printf("\nbase45(%s) ", (char*)out);
printf("\n%d",err);
//decompressione zlib
ucompSize_out= strlen(out)+1;
compSize_out= compressBound(ucompSize_out);
err=uncompress ((Byte *)u_out, &ucompSize_out, (const Byte *) out, compSize_out );
printf("\nzlib(\"%s\") ", (char*)u_out);
printf("\n%d",err);
when I run this code it returns me BUF_ERROR (-5). I read on the Zlib guide that it is a problem of space for output or input but I can not figure out how to fix it
for completeness load also the functions recalled
int ZEXPORT uncompress2 (dest, destLen, source, sourceLen)
Bytef *dest;
uLongf *destLen;
const Bytef *source;
uLong *sourceLen;
{
z_stream stream;
int ZEXPORT inflateInit2_(strm, windowBits, version, stream_size)
z_streamp strm;
int windowBits;
const char *version;
int stream_size;
{
int ret;
struct inflate_state FAR *state;
if (version == Z_NULL || version[0] != ZLIB_VERSION[0] ||
stream_size != (int)(sizeof(z_stream)))
return Z_VERSION_ERROR;
if (strm == Z_NULL) return Z_STREAM_ERROR;
strm->msg = Z_NULL; /* in case we return an error */
if (strm->zalloc == (alloc_func)0) {
}
if (strm->zfree == (free_func)0)
state = (struct inflate_state FAR *)
ZALLOC(strm, 1, sizeof(struct inflate_state));
if (state == Z_NULL) return Z_MEM_ERROR;
Tracev((stderr, "inflate: allocated\n"));
strm->state = (struct internal_state FAR *)state;
state->strm = strm;
state->window = Z_NULL;
state->mode = HEAD; /* to pass state test in inflateReset2() */
ret = inflateReset2(strm, windowBits);
if (ret != Z_OK) {
ZFREE(strm, state);
strm->state = Z_NULL;
}
return ret;
}
int ZEXPORT inflateInit_(strm, version, stream_size)
z_streamp strm;
const char *version;
int stream_size;
{
return inflateInit2_(strm, DEF_WBITS, version, stream_size);
}
int err;
const uInt max = (uInt)-1;
uLong len, left;
Byte buf[1]; /* for detection of incomplete stream when *destLen == 0 */
len = *sourceLen;
if (*destLen) {
left = *destLen;
*destLen = 0;
}
else {
left = 1;
dest = buf;
}
stream.next_in = (z_const Bytef *)source;
stream.avail_in = 0;
stream.zalloc = (alloc_func)0;
stream.zfree = (free_func)0;
stream.opaque = (voidpf)0;
err = inflateInit2(&stream);
if (err != Z_OK) return err;
stream.next_out = dest;
stream.avail_out = 0;
do {
if (stream.avail_out == 0) {
stream.avail_out = left > (uLong)max ? max : (uInt)left;
left -= stream.avail_out;
}
if (stream.avail_in == 0) {
stream.avail_in = len > (uLong)max ? max : (uInt)len;
len -= stream.avail_in;
}
err = inflate(&stream, Z_NO_FLUSH);
} while (err == Z_OK);
*sourceLen -= len + stream.avail_in;
if (dest != buf)
*destLen = stream.total_out;
else if (stream.total_out && err == Z_BUF_ERROR)
left = 1;
inflateEnd(&stream);
return err == Z_STREAM_END ? Z_OK :
err == Z_NEED_DICT ? Z_DATA_ERROR :
err == Z_BUF_ERROR && left + stream.avail_out ? Z_DATA_ERROR :
err;
}
int ZEXPORT uncompress (dest, destLen, source, sourceLen)
Bytef *dest;
uLongf *destLen;
const Bytef *source;
uLong sourceLen;
{
return uncompress2(dest, destLen, source, &sourceLen);
}
I'm trying to finish my network programming practice. And I came through this problem which I couldn't fix. It might seem stupid but I had spent an afternoon on it. I would really appreciate if anyone could help me out.
Here is the code, the error is within #ifdef process_conn_server_2 segment.
#include <stdio.h>
#include <sys/uio.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <fcntl.h>
#include <sys/types.h>
#include "process_num.c"
#define process_conn_client_2
#define process_conn_server_2
static struct iovec *vs = NULL,
*vc = NULL;
void sig_process(int signo)
{
printf("Catch ax exit signal\n");
free(vc);
free(vs);
_exit(0);
}
void sig_pipe(int signo)
{
printf("Catch a SIGPIPE signal\n");
free(vc);
free(vs);
_exit(0);
}
#ifdef process_conn_client_0
void process_conn_client(int s)
{
ssize_t size = 0;
char buffer[1024];
for (;;)
{
size = read(0, buffer, 1024);
// size = recv(s, buffer, 1024, 0);
if (size > 0)
{
send(s, buffer, size, 0);
size = recv(s, buffer, 1024, 0);
write(1, buffer, size);
}
}
}
#endif // read、send、write
#ifdef process_conn_client_1
void process_conn_client(int s)
{
char buffer[30];
ssize_t size = 0;
struct iovec *v = (struct iovec *)malloc(3 * sizeof(struct iovec));
if (!v)
{
printf("Not enough memory\n");
return;
}
vc = v;
v[0].iov_base = buffer;
v[1].iov_base = buffer + 10;
v[2].iov_base = buffer + 20;
v[0].iov_len = v[1].iov_len = v[2].iov_len = 10;
int i = 0;
for (;;)
{
size = read(0, v[0].iov_base, 10);
if (size > 0)
{
v[0].iov_len = size;
writev(s, v, 1);
v[0].iov_len = v[1].iov_len = v[2].iov_len = 10;
size = readv(s, v, 3);
for (i = 0; i < 3; i++)
{
if (v[i].iov_len > 0)
{
write(1, v[i].iov_base, v[i].iov_len);
}
}
}
}
}
#endif // read writev readv
#ifdef process_conn_client_2
void process_conn_client(int s)
{
char buffer[30];
ssize_t size = 0;
struct msghdr msg;
struct iovec *v = (struct iovec *)malloc(3 * sizeof(struct iovec));
if (!v)
{
perror("wrong: allocate memory\n");
return;
}
msg.msg_name = NULL;
msg.msg_namelen = 0;
msg.msg_control = NULL;
msg.msg_controllen = 0;
msg.msg_iov = v;
msg.msg_iovlen = 3;
msg.msg_flags = 0;
vc = v;
v[0].iov_base = buffer;
v[1].iov_base = buffer + 10;
v[2].iov_base = buffer + 20;
v[0].iov_len = v[1].iov_len = v[2].iov_len = 10;
// int fd;
for (;;)
{
// fd = open("firstfile.txt", O_RDONLY, 0666);
size = read(0, v[0].iov_base, 10);
printf("%d size\n", size);
if (size > 0)
{
v[0].iov_len = size;
if (sendmsg(s, &msg, 0) < 0)
{
perror("");
return;
}
v[0].iov_len = v[1].iov_len = v[2].iov_len = 10;
memset(v[0].iov_base, '\0', v[0].iov_len);
memset(v[1].iov_base, '\0', v[1].iov_len);
memset(v[2].iov_base, '\0', v[2].iov_len);
size = recvmsg(s, &msg, 0);
for (int i = 0; i < 3; i++)
{
if (v[i].iov_len > 0)
{
write(1, v[i].iov_base, v[i].iov_len);
write(1, '\n', 1);
}
}
memset(v[0].iov_base, '\0', v[0].iov_len);
memset(v[1].iov_base, '\0', v[1].iov_len);
memset(v[2].iov_base, '\0', v[2].iov_len);
}
}
#endif // sendmsg recvmsg
#ifdef process_conn_server_0
void process_conn_server(int s)
{
ssize_t size = 0;
char buffer[1024];
float result;
for (;;)
{
// size = read(s, buffer, 1024);
size = recv(s, buffer, 1024, 0);
if (size == 0)
{
return;
}
printf("received %s", buffer);
result = process_num(buffer);
if (result == 65535)
{
sprintf(buffer, "%d bytes in total.\n", size);
}
else
{
printf("%f\n", result);
sprintf(buffer, "the result is %f.\n", result);
}
//write(s, buffer, strlen(buffer) + 1);
send(s, buffer, strlen(buffer) + 1, 0);
memset(buffer, '\0', sizeof(buffer));
}
}
#endif //recv send
#ifdef process_conn_server_1
void process_conn_server(int s)
{
char buffer[30];
ssize_t size = 0;
struct iovec *v = (struct iovec *)malloc(3 * sizeof(struct iovec));
if (!v)
{
printf("Not enough memory\n");
return;
}
vs = v;
v[0].iov_base = buffer;
v[1].iov_base = buffer + 10;
v[2].iov_base = buffer + 20;
v[0].iov_len = v[1].iov_len = v[2].iov_len = 10;
for (;;)
{
size = readv(s, v, 3);
if (size == 0)
{
return;
}
sprintf(v[0].iov_base, "%d ", size);
sprintf(v[1].iov_base, "bytes alt");
sprintf(v[2].iov_base, "ogether\n");
v[0].iov_len = strlen(v[0].iov_base);
v[1].iov_len = strlen(v[1].iov_base);
v[2].iov_len = strlen(v[2].iov_base);
writev(s, v, 3);
}
}
#endif // readv writev
#ifdef process_conn_server_2
void process_conn_server(int s)
{ //this is where the error appears
char buffer[30];
ssize_t size = 0;
struct msghdr msg;
struct iovec *v = (struct iovec *)malloc(3 * sizeof(struct iovec));
if (!v)
{
perror("wrong: allocate memory\n");
return;
}
msg.msg_name = NULL;
msg.msg_namelen = 0;
msg.msg_control = NULL;
msg.msg_controllen = 0;
msg.msg_iov = v;
msg.msg_iovlen = 3;
msg.msg_flags = 0;
vs = v;
v[0].iov_base = buffer;
v[1].iov_base = buffer + 10;
v[2].iov_base = buffer + 20;
v[0].iov_len = v[1].iov_len = v[2].iov_len = 10;
for (;;)
{
size = recvmsg(s, &msg, 0);
if (size == 0)
{
return;
}
sprintf(v[0].iov_base, "%d ", size);
sprintf(v[1].iov_base, "bytes alt");
sprintf(v[2].iov_base, "ogether\n");
v[0].iov_len = strlen(v[0].iov_base);
v[1].iov_len = strlen(v[1].iov_base);
v[2].iov_len = strlen(v[2].iov_base);
for (int i = 0; i < 3; i++)
{
if (v[i].iov_len > 0)
{
write(1, v[i].iov_base, v[i].iov_len);
write(1, '\n', 1);
}
}
sendmsg(s, &msg, 0);
memset(v[0].iov_base, '\0', v[0].iov_len);
memset(v[1].iov_base, '\0', v[1].iov_len);
memset(v[2].iov_base, '\0', v[2].iov_len);
}
}
#endif
I dont't know if this would be of any help but the code works just fine when I
define process_conn_server/client 0/1 instead of 2.
when process_conn_client_2 is defined, you don't seem to close process_conn_client(), therefore opening another function after that gives you an error. You can see that from the indentation
Just for total clarification. There is missing a closing bracket } at the end of the definition of process_conn_client_2 to terminate the function definition. Hence the error.
I marked the place of issue with the correct placed } in this snippet:
#ifdef process_conn_client_2
void process_conn_client(int s)
{
char buffer[30];
ssize_t size = 0;
struct msghdr msg;
struct iovec *v = (struct iovec *)malloc(3 * sizeof(struct iovec));
if (!v)
{
perror("wrong: allocate memory\n");
return;
}
msg.msg_name = NULL;
msg.msg_namelen = 0;
msg.msg_control = NULL;
msg.msg_controllen = 0;
msg.msg_iov = v;
msg.msg_iovlen = 3;
msg.msg_flags = 0;
vc = v;
v[0].iov_base = buffer;
v[1].iov_base = buffer + 10;
v[2].iov_base = buffer + 20;
v[0].iov_len = v[1].iov_len = v[2].iov_len = 10;
// int fd;
for (;;)
{
// fd = open("firstfile.txt", O_RDONLY, 0666);
size = read(0, v[0].iov_base, 10);
printf("%d size\n", size);
if (size > 0)
{
v[0].iov_len = size;
if (sendmsg(s, &msg, 0) < 0)
{
perror("");
return;
}
v[0].iov_len = v[1].iov_len = v[2].iov_len = 10;
memset(v[0].iov_base, '\0', v[0].iov_len);
memset(v[1].iov_base, '\0', v[1].iov_len);
memset(v[2].iov_base, '\0', v[2].iov_len);
size = recvmsg(s, &msg, 0);
for (int i = 0; i < 3; i++)
{
if (v[i].iov_len > 0)
{
write(1, v[i].iov_base, v[i].iov_len);
write(1, '\n', 1);
}
}
memset(v[0].iov_base, '\0', v[0].iov_len);
memset(v[1].iov_base, '\0', v[1].iov_len);
memset(v[2].iov_base, '\0', v[2].iov_len);
}
}
} // <------- HERE
#endif // sendmsg recvmsg
I voted to close this question as caused by typo.
i have to do with my friend a program in C for my school.
The problem is, when i would malloc a pointer, it doesn't work, and the application will crashed.
But not in debug mod. In debug mod, it works.
This is a part of my code:
#include <bplus.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#define LOG "log.txt"
#define LOGIDX "log.idx"
struct event {
time_t nb;
char *username;
int type;
char *message;
};
struct eventlist {
struct event event;
struct eventlist *nextelem;
};
struct eventlist *getEventList(time_t date);
void insert(struct eventlist *list, struct eventlist *event);
struct event getEventFromString(char *str);
char *getLine(FILE *file);
int file_exists(const char *fname);
char *dechiffrer(const char *pChaineChiffree);
int main(void) {
time_t timenow = time(NULL);
struct tm *tm = gmtime(&timenow);
tm->tm_hour = 0;
tm->tm_min = 0;
tm->tm_sec = 0;
time_t time = mktime(tm);
struct eventlist *list = getEventList(time);
return 0;
}
struct eventlist *getEventList(time_t date) {
int end = 0;
FILE *file = NULL;
char str[20];
char *line = NULL;
char *uncode = NULL;
ENTRY e;
IX_DESC faddress;
struct eventlist *list = NULL; // Liste a retourner
struct event *event = NULL; // Contient l'evenement
struct eventlist *templist = NULL; // Contient l'evenement a mettre dans list
// On ouvre / crée le fichier .idx
if (file_exists(LOGIDX))
open_index(LOGIDX, &faddress, 0);
else
make_index(LOGIDX, &faddress, 0);
// On ouvre le fichier de log
if ((file = fopen(LOG, "rb")) != NULL) {
// On met dans e.key le temps
sprintf(str, "%d", (int) date);
strcpy(e.key, str);
if (find_key(&e, &faddress)) { // Si la clé existe
fseek(file, e.recptr, SEEK_SET); // On se positionne
line = getLine(file); // On récupère la ligne
while (!feof(file) && !end) { // Boucle principale
printf("\ngetEventList 1");
if (line != NULL) {
uncode = dechiffrer(line); // On déchiffre la ligne
printf("\ngetEventList 2");
event = (struct event *) malloc(sizeof(struct event *) * 1); // On alloue de la place
printf("\ngetEventList 3");
if (event) {
*event = getEventFromString(uncode); // On la transforme en structure
printf("\ngetEventList 4");
if (event->nb < date + 86400) {
templist = (struct eventlist *) malloc(sizeof(struct eventlist *) * 1);
printf("\ngetEventList 5");
if (templist) {
templist->event = *event;
templist->nextelem = NULL;
printf("\ngetEventList 6");
if (list == NULL)
list = templist;
else
insert(list, templist);
printf("\ngetEventList 7");
line = getLine(file); // On récupère la ligne
printf("\ngetEventList 8");
} else {
list = NULL;
end = 1;
}
} else
end = 1;
} else {
list = NULL;
end = 1;
}
} else
end = 1;
}
} else { // Sinon, on affiche un message
list = NULL;
printf("\nErreur: Clé non trouvée !");
}
fclose(file);
} else {
list = NULL;
printf("\nErreur lors de l'ouverture du fichier !");
}
return list;
}
void insert(struct eventlist *list, struct eventlist *event) {
struct eventlist *temp = list;
struct eventlist *lasttemp = NULL;
printf("\n(%s %s)", temp->event.username, event->event.username);
while (temp->nextelem != NULL && stricmp(temp->event.username, event->event.username)) {
temp = temp->nextelem;
}
lasttemp = temp;
while (temp != NULL && !stricmp(temp->event.username, event->event.username)) {
lasttemp = temp;
temp = temp->nextelem;
}
event->nextelem = temp;
lasttemp->nextelem = event;
}
struct event getEventFromString(char *str) {
struct event event;
event.nb = 0;
event.type = 0;
event.username = NULL;
event.message = NULL;
int time;
int type;
char *username = (char *) malloc(sizeof(char *) * strlen(str));
char *message = (char *) malloc(sizeof(char *) * strlen(str));
if (sscanf(str, "%d %d %s %[^\n]s", &(time), &(type), username, message)) {
event.nb = (time_t) time;
event.type = type;
event.username = username;
event.message = message;
}
return event;
}
char *getLine(FILE *file) {
char *line = NULL;
unsigned char c;
int end = 0;
int ln = 0;
printf("\ngetLine 1");
line = (char *) malloc(sizeof(char *) * 1);
printf("\ngetLine 2");
if (line != NULL) {
while(!feof(file) && !end) {
c = fgetc(file);
if (c != '\n' && c != '\r') {
printf("\nDEBUG: %c %d %s", c, ln, line);
line = (char *) realloc(line, sizeof(char *) * (ln + 2));
if (line != NULL) {
line[ln++] = c;
line[ln] = '\0';
} else
end = 1;
} else
end = 1;
}
line[ln] = '\0';
}
if (line[0] == '\0' || line[1] == '\0')
line = NULL;
return line;
}
int file_exists(const char *fname) {
FILE *file;
int returncode = 0;
if ((file = fopen(fname, "r"))) {
fclose(file);
returncode = 1;
}
return returncode;
}
char *dechiffrer(const char *pChaineChiffree) {
char *dechiff;
unsigned char car;
unsigned int i;
dechiff = malloc(strlen(pChaineChiffree) + 1);
for (i = 0; pChaineChiffree[i] != '\0'; i++) {
car = pChaineChiffree[i];
car = (car & 0x0F) << 4 | (car & 0xF0) >> 4;
// car -= 0x55;
dechiff[i] = car;
}
dechiff[i] = '\0';
return dechiff;
}
I think it's a bufferoverflow, but i don't know where is the problem, and why it's bugged.
The crash occured in this malloc:
printf("\ngetLine 1");
line = (char *) malloc(sizeof(char *) * 1);
printf("\ngetLine 2");
Please help me
Thanks
0ddlyoko
EDIT:
Ok i've found the problem, it was with all my sizeof(XXX *), i've just changed this to sizeof(XXX).
Thanks !
I am trying to get a simple django app up on Http Server. The server is IBM Websphere Application Server. I have successfully compiled mod_scgi.c to the iseries.
I proceeded to create a server and edit the configuration file with the following code:
#Load the mod_scgi module
LoadModule scgi_module /qsys.lib/qgpl.lib/mod_scgi.srvpgm
# Set up location to be server by an SCGI server process
SCGIMount /dynamic 127.0.0.1:8080
This produces an error on the configuration file: "Directive name "SCGIMount" is not recognized."
I am not sure how to proceed from here. Also, the mod_scgi.c file has been modified to allow it to be compiled to the iseries. I have provided the code below:
/* mod_scgi.c
*
* Apache 2 implementation of the SCGI protocol.
*
*/
#define MOD_SCGI_VERSION "1.14"
#define SCGI_PROTOCOL_VERSION "1"
#include "ap_config.h"
#include "apr_version.h"
#include "apr_lib.h"
#include "apr_strings.h"
#include "httpd.h"
#include "http_config.h"
#include "http_core.h"
#include "http_request.h"
#include "http_log.h"
#include "http_protocol.h"
#include "util_script.h"
#ifdef AS400
#include <strings.h>
#endif
#define DEFAULT_TIMEOUT 60 /* default socket timeout */
#define UNSET 0
#define ENABLED 1
#define DISABLED 2
#if APR_MAJOR_VERSION == 0
#define apr_socket_send apr_send
#define GET_PORT(port, addr) apr_sockaddr_port_get(&(port), addr)
#define CREATE_SOCKET(sock, family, pool) \
apr_socket_create(sock, family, SOCK_STREAM, pool)
#else
#define GET_PORT(port, addr) ((port) = (addr)->port)
#define CREATE_SOCKET(sock, family, pool) \
apr_socket_create(sock, family, SOCK_STREAM, APR_PROTO_TCP, pool)
#endif
typedef struct {
char *path;
char *addr;
apr_port_t port;
} mount_entry;
/*
* Configuration record. Used per-directory configuration data.
*/
typedef struct {
mount_entry mount;
int enabled; /* mod_scgi is enabled from this directory */
int timeout;
} scgi_cfg;
/* Server level configuration */
typedef struct {
apr_array_header_t *mounts;
int timeout;
} scgi_server_cfg;
/*
* Declare ourselves so the configuration routines can find and know us.
* We'll fill it in at the end of the module.
*/
module AP_MODULE_DECLARE_DATA scgi_module;
/*
* Locate our directory configuration record for the current request.
*/
static scgi_cfg *
our_dconfig(request_rec *r)
{
return (scgi_cfg *) ap_get_module_config(r->per_dir_config, &scgi_module);
}
static scgi_server_cfg *our_sconfig(server_rec *s)
{
return (scgi_server_cfg *) ap_get_module_config(s->module_config,
&scgi_module);
}
static int
mount_entry_matches(const char *url, const char *prefix,
const char **path_info)
{
int i;
for (i=0; prefix[i] != '\0'; i++) {
if (url[i] == '\0' || url[i] != prefix[i])
return 0;
}
if (url[i] == '\0' || url[i] == '/') {
*path_info = url + i;
return 1;
}
return 0;
}
static int scgi_translate(request_rec *r)
{
scgi_cfg *cfg = our_dconfig(r);
if (cfg->enabled == DISABLED) {
return DECLINED;
}
if (cfg->mount.addr != UNSET) {
ap_assert(cfg->mount.port != UNSET);
r->handler = "scgi-handler";
r->filename = r->uri;
return OK;
}
else {
int i;
scgi_server_cfg *scfg = our_sconfig(r->server);
mount_entry *entries = (mount_entry *) scfg->mounts->elts;
for (i = 0; i < scfg->mounts->nelts; ++i) {
const char *path_info;
mount_entry *mount = &entries[i];
if (mount_entry_matches(r->uri, mount->path, &path_info)) {
r->handler = "scgi-handler";
r->path_info = apr_pstrdup(r->pool, path_info);
r->filename = r->uri;
ap_set_module_config(r->request_config, &scgi_module, mount);
return OK;
}
}
}
return DECLINED;
}
static int scgi_map_location(request_rec *r)
{
if (r->handler && strcmp(r->handler, "scgi-handler") == 0) {
return OK; /* We don't want directory walk. */
}
return DECLINED;
}
static void log_err(const char *file, int line, request_rec *r,
apr_status_t status, const char *msg)
{
ap_log_rerror(file, line, APLOG_ERR, status, r, "scgi: %s", msg);
}
static void log_debug(const char *file, int line, request_rec *r, const
char *msg)
{
ap_log_rerror(file, line, APLOG_DEBUG, APR_SUCCESS, r, msg);
}
static char *http2env(apr_pool_t *p, const char *name)
{
char *env_name = apr_pstrcat(p, "HTTP_", name, NULL);
char *cp;
for (cp = env_name + 5; *cp != 0; cp++) {
if (*cp == '-') {
*cp = '_';
}
else {
*cp = apr_toupper(*cp);
}
}
return env_name;
}
static char *lookup_name(apr_table_t *t, const char *name)
{
const apr_array_header_t *hdrs_arr = apr_table_elts(t);
apr_table_entry_t *hdrs = (apr_table_entry_t *) hdrs_arr->elts;
int i;
for (i = 0; i < hdrs_arr->nelts; ++i) {
if (hdrs[i].key == NULL)
continue;
if (strcasecmp(hdrs[i].key, name) == 0)
return hdrs[i].val;
}
return NULL;
}
static char *lookup_header(request_rec *r, const char *name)
{
return lookup_name(r->headers_in, name);
}
static void add_header(apr_table_t *t, const char *name, const char *value)
{
if (name != NULL && value != NULL)
apr_table_addn(t, name, value);
}
static int find_path_info(const char *uri, const char *path_info)
{
int n;
n = strlen(uri) - strlen(path_info);
ap_assert(n >= 0);
return n;
}
/* This code is a duplicate of what's in util_script.c. We can't use
* r->unparsed_uri because it gets changed if there was a redirect. */
static char *original_uri(request_rec *r)
{
char *first, *last;
if (r->the_request == NULL) {
return (char *) apr_pcalloc(r->pool, 1);
}
first = r->the_request; /* use the request-line */
while (*first && !apr_isspace(*first)) {
++first; /* skip over the method */
}
while (apr_isspace(*first)) {
++first; /* and the space(s) */
}
last = first;
while (*last && !apr_isspace(*last)) {
++last; /* end at next whitespace */
}
return apr_pstrmemdup(r->pool, first, last - first);
}
/* buffered socket implementation (buckets are overkill) */
#define BUFFER_SIZE 8000
struct sockbuff {
apr_socket_t *sock;
char buf[BUFFER_SIZE];
int used;
};
static void binit(struct sockbuff *s, apr_socket_t *sock)
{
s->sock = sock;
s->used = 0;
}
static apr_status_t sendall(apr_socket_t *sock, char *buf, apr_size_t len)
{
apr_status_t rv;
apr_size_t n;
while (len > 0) {
n = len;
if ((rv = apr_socket_send(sock, buf, &n))) return rv;
buf += n;
len -= n;
}
return APR_SUCCESS;
}
static apr_status_t bflush(struct sockbuff *s)
{
apr_status_t rv;
ap_assert(s->used >= 0 && s->used <= BUFFER_SIZE);
if (s->used) {
if ((rv = sendall(s->sock, s->buf, s->used))) return rv;
s->used = 0;
}
return APR_SUCCESS;
}
static apr_status_t bwrite(struct sockbuff *s, char *buf, apr_size_t len)
{
apr_status_t rv;
if (len >= BUFFER_SIZE - s->used) {
if ((rv = bflush(s))) return rv;
while (len >= BUFFER_SIZE) {
if ((rv = sendall(s->sock, buf, BUFFER_SIZE))) return rv;
buf += BUFFER_SIZE;
len -= BUFFER_SIZE;
}
}
if (len > 0) {
ap_assert(len < BUFFER_SIZE - s->used);
memcpy(s->buf + s->used, buf, len);
s->used += len;
}
return APR_SUCCESS;
}
static apr_status_t bputs(struct sockbuff *s, char *buf)
{
return bwrite(s, buf, strlen(buf));
}
static apr_status_t bputc(struct sockbuff *s, char c)
{
char buf[1];
buf[0] = c;
return bwrite(s, buf, 1);
}
static apr_status_t
send_headers(request_rec *r, struct sockbuff *s)
{
/* headers to send */
apr_table_t *t;
const apr_array_header_t *hdrs_arr, *env_arr;
apr_table_entry_t *hdrs, *env;
unsigned long int n = 0;
char *buf;
int i;
apr_status_t rv = 0;
apr_port_t port = 0;
GET_PORT(port, r->connection->remote_addr);
log_debug(APLOG_MARK,r, "sending headers");
t = apr_table_make(r->pool, 40);
if (!t)
return APR_ENOMEM;
/* CONTENT_LENGTH must come first and always be present */
buf = lookup_header(r, "Content-Length");
if (buf == NULL)
buf = "0";
add_header(t, "CONTENT_LENGTH", buf);
add_header(t, "SCGI", SCGI_PROTOCOL_VERSION);
add_header(t, "SERVER_SOFTWARE", ap_get_server_version());
add_header(t, "SERVER_PROTOCOL", r->protocol);
add_header(t, "SERVER_NAME", ap_get_server_name(r));
add_header(t, "SERVER_ADMIN", r->server->server_admin);
add_header(t, "SERVER_ADDR", r->connection->local_ip);
add_header(t, "SERVER_PORT", apr_psprintf(r->pool, "%u",
ap_get_server_port(r)));
add_header(t, "REMOTE_ADDR", r->connection->remote_ip);
add_header(t, "REMOTE_PORT", apr_psprintf(r->pool, "%d", port));
add_header(t, "REMOTE_USER", r->user);
add_header(t, "REQUEST_METHOD", r->method);
add_header(t, "REQUEST_URI", original_uri(r));
add_header(t, "QUERY_STRING", r->args ? r->args : "");
if (r->path_info) {
int path_info_start = find_path_info(r->uri, r->path_info);
add_header(t, "SCRIPT_NAME", apr_pstrndup(r->pool, r->uri,
path_info_start));
add_header(t, "PATH_INFO", r->path_info);
}
else {
/* skip PATH_INFO, don't know it */
add_header(t, "SCRIPT_NAME", r->uri);
}
add_header(t, "CONTENT_TYPE", lookup_header(r, "Content-type"));
add_header(t, "DOCUMENT_ROOT", ap_document_root(r));
/* HTTP headers */
hdrs_arr = apr_table_elts(r->headers_in);
hdrs = (apr_table_entry_t *) hdrs_arr->elts;
for (i = 0; i < hdrs_arr->nelts; ++i) {
if (hdrs[i].key) {
add_header(t, http2env(r->pool, hdrs[i].key), hdrs[i].val);
}
}
/* environment variables */
env_arr = apr_table_elts(r->subprocess_env);
env = (apr_table_entry_t*) env_arr->elts;
for (i = 0; i < env_arr->nelts; ++i) {
add_header(t, env[i].key, env[i].val);
}
hdrs_arr = apr_table_elts(t);
hdrs = (apr_table_entry_t*) hdrs_arr->elts;
/* calculate length of header data (including nulls) */
for (i = 0; i < hdrs_arr->nelts; ++i) {
n += strlen(hdrs[i].key) + 1;
n += strlen(hdrs[i].val) + 1;
}
buf = apr_psprintf(r->pool, "%lu:", n);
if (!buf)
return APR_ENOMEM;
rv = bputs(s, buf);
if (rv)
return rv;
for (i = 0; i < hdrs_arr->nelts; ++i) {
rv = bputs(s, hdrs[i].key);
if (rv) return rv;
rv = bputc(s, '\0');
if (rv) return rv;
rv = bputs(s, hdrs[i].val);
if (rv) return rv;
rv = bputc(s, '\0');
if (rv) return rv;
}
rv = bputc(s, ',');
if (rv)
return rv;
return APR_SUCCESS;
}
static apr_status_t send_request_body(request_rec *r, struct sockbuff *s)
{
if (ap_should_client_block(r)) {
char buf[BUFFER_SIZE];
apr_status_t rv;
apr_off_t len;
while ((len = ap_get_client_block(r, buf, sizeof buf)) > 0) {
if ((rv = bwrite(s, buf, len))) return rv;
}
if (len == -1)
return HTTP_INTERNAL_SERVER_ERROR; /* what to return? */
}
return APR_SUCCESS;
}
#define CONFIG_VALUE(value, fallback) ((value) != UNSET ? (value) : (fallback))
static apr_status_t
open_socket(apr_socket_t **sock, request_rec *r)
{
int timeout;
int retries = 4;
int sleeptime = 1;
apr_status_t rv;
apr_sockaddr_t *sockaddr;
scgi_server_cfg *scfg = our_sconfig(r->server);
scgi_cfg *cfg = our_dconfig(r);
mount_entry *m = (mount_entry *) ap_get_module_config(r->request_config,
&scgi_module);
if (!m) {
m = &cfg->mount;
}
timeout = CONFIG_VALUE(cfg->timeout, CONFIG_VALUE(scfg->timeout,
DEFAULT_TIMEOUT));
rv = apr_sockaddr_info_get(&sockaddr,
CONFIG_VALUE(m->addr, "localhost"),
APR_UNSPEC,
CONFIG_VALUE(m->port, 4000),
0,
r->pool);
if (rv) {
log_err(APLOG_MARK, r, rv, "apr_sockaddr_info_get() error");
return rv;
}
restart:
*sock = NULL;
rv = CREATE_SOCKET(sock, sockaddr->family, r->pool);
if (rv) {
log_err(APLOG_MARK, r, rv, "apr_socket_create() error");
return rv;
}
rv = apr_socket_timeout_set(*sock, apr_time_from_sec(timeout));
if (rv) {
log_err(APLOG_MARK, r, rv, "apr_socket_timeout_set() error");
return rv;
}
rv = apr_socket_connect(*sock, sockaddr);
if (rv) {
apr_socket_close(*sock);
if ((APR_STATUS_IS_ECONNREFUSED(rv) |
APR_STATUS_IS_EINPROGRESS(rv)) && retries > 0) {
/* server may be temporarily down, retry */
ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_DEBUG, rv, r,
"scgi: connection failed, retrying");
apr_sleep(apr_time_from_sec(sleeptime));
--retries;
sleeptime *= 2;
goto restart;
}
log_err(APLOG_MARK, r, rv, "scgi: can't connect to server");
return rv;
}
#ifdef APR_TCP_NODELAY
/* disable Nagle, we don't send small packets */
apr_socket_opt_set(*sock, APR_TCP_NODELAY, 1);
#endif
return APR_SUCCESS;
}
#ifdef AS400
static int getsfunc_BRIGADE(char *buf, int len, void *arg)
{
apr_bucket_brigade *bb = (apr_bucket_brigade *)arg;
const char *dst_end = buf + len - 1; /* leave room for terminating null */
char *dst = buf;
apr_bucket *e = APR_BRIGADE_FIRST(bb);
apr_status_t rv;
int done = 0;
while ((dst < dst_end) && !done && e != APR_BRIGADE_SENTINEL(bb)
&& !APR_BUCKET_IS_EOS(e)) {
const char *bucket_data;
apr_size_t bucket_data_len;
const char *src;
const char *src_end;
apr_bucket * next;
rv = apr_bucket_read(e, &bucket_data, &bucket_data_len,
APR_BLOCK_READ);
if (rv != APR_SUCCESS || (bucket_data_len == 0)) {
*dst = '\0';
return APR_STATUS_IS_TIMEUP(rv) ? -1 : 0;
}
src = bucket_data;
src_end = bucket_data + bucket_data_len;
while ((src < src_end) && (dst < dst_end) && !done) {
if (*src == '\n') {
done = 1;
}
else if (*src != '\r') {
*dst++ = *src;
}
src++;
}
if (src < src_end) {
apr_bucket_split(e, src - bucket_data);
}
next = APR_BUCKET_NEXT(e);
APR_BUCKET_REMOVE(e);
apr_bucket_destroy(e);
e = next;
}
*dst = 0;
return done;
}
#endif
static int scgi_handler(request_rec *r)
{
apr_status_t rv = 0;
int http_status = 0;
struct sockbuff s;
apr_socket_t *sock;
apr_bucket_brigade *bb = NULL;
apr_bucket *b = NULL;
const char *location;
if (strcmp(r->handler, "scgi-handler"))
return DECLINED;
http_status = ap_setup_client_block(r, REQUEST_CHUNKED_ERROR);
if (http_status != OK)
return http_status;
log_debug(APLOG_MARK, r, "connecting to server");
rv = open_socket(&sock, r);
if (rv) {
return HTTP_INTERNAL_SERVER_ERROR;
}
binit(&s, sock);
rv = send_headers(r, &s);
if (rv) {
log_err(APLOG_MARK, r, rv, "error sending request headers");
return HTTP_INTERNAL_SERVER_ERROR;
}
rv = send_request_body(r, &s);
if (rv) {
log_err(APLOG_MARK, r, rv, "error sending request body");
return HTTP_INTERNAL_SERVER_ERROR;
}
rv = bflush(&s);
if (rv) {
log_err(APLOG_MARK, r, rv, "error sending request");
return HTTP_INTERNAL_SERVER_ERROR;
}
log_debug(APLOG_MARK, r, "reading response headers");
bb = apr_brigade_create(r->connection->pool, r->connection->bucket_alloc);
b = apr_bucket_socket_create(sock, r->connection->bucket_alloc);
APR_BRIGADE_INSERT_TAIL(bb, b);
b = apr_bucket_eos_create(r->connection->bucket_alloc);
APR_BRIGADE_INSERT_TAIL(bb, b);
#ifdef AS400
rv = ap_scan_script_header_err_core(r, NULL, getsfunc_BRIGADE, bb);
#else
rv = ap_scan_script_header_err_brigade(r, bb, NULL);
#endif
if (rv) {
if (rv == HTTP_INTERNAL_SERVER_ERROR) {
log_err(APLOG_MARK, r, rv, "error reading response headers");
}
else {
/* Work around an Apache bug whereby the returned status is
* ignored and status_line is used instead. This bug is
* present at least in 2.0.54.
*/
r->status_line = NULL;
}
apr_brigade_destroy(bb);
return rv;
}
location = apr_table_get(r->headers_out, "Location");
if (location && location[0] == '/' &&
((r->status == HTTP_OK) || ap_is_HTTP_REDIRECT(r->status))) {
apr_brigade_destroy(bb);
/* Internal redirect -- fake-up a pseudo-request */
r->status = HTTP_OK;
/* This redirect needs to be a GET no matter what the original
* method was.
*/
r->method = apr_pstrdup(r->pool, "GET");
r->method_number = M_GET;
/* We already read the message body (if any), so don't allow
* the redirected request to think it has one. We can ignore
* Transfer-Encoding, since we used REQUEST_CHUNKED_ERROR.
*/
apr_table_unset(r->headers_in, "Content-Length");
ap_internal_redirect_handler(location, r);
return OK;
}
rv = ap_pass_brigade(r->output_filters, bb);
if (rv) {
log_err(APLOG_MARK, r, rv, "ap_pass_brigade()");
return HTTP_INTERNAL_SERVER_ERROR;
}
return OK;
}
static int scgi_init(apr_pool_t *p, apr_pool_t *plog, apr_pool_t *ptemp,
server_rec *base_server)
{
ap_add_version_component(p, "mod_scgi/" MOD_SCGI_VERSION);
return OK;
}
static void *
create_dir_config(apr_pool_t *p, char *dirspec)
{
scgi_cfg *cfg = apr_pcalloc(p, sizeof(scgi_cfg));
cfg->enabled = UNSET;
cfg->mount.addr = UNSET;
cfg->mount.port = UNSET;
cfg->timeout = UNSET;
return cfg;
}
#define MERGE(b, n, a) (n->a == UNSET ? b->a : n->a)
static void *
merge_dir_config(apr_pool_t *p, void *basev, void *newv)
{
scgi_cfg* cfg = apr_pcalloc(p, sizeof(scgi_cfg));
scgi_cfg* base = basev;
scgi_cfg* new = newv;
cfg->enabled = MERGE(base, new, enabled);
cfg->mount.addr = MERGE(base, new, mount.addr);
cfg->mount.port = MERGE(base, new, mount.port);
cfg->timeout = MERGE(base, new, timeout);
return cfg;
}
static void *
create_server_config(apr_pool_t *p, server_rec *s)
{
scgi_server_cfg *c =
(scgi_server_cfg *) apr_pcalloc(p, sizeof(scgi_server_cfg));
c->mounts = apr_array_make(p, 20, sizeof(mount_entry));
c->timeout = UNSET;
return c;
}
static void *
merge_server_config(apr_pool_t *p, void *basev, void *overridesv)
{
scgi_server_cfg *c = (scgi_server_cfg *)
apr_pcalloc(p, sizeof(scgi_server_cfg));
scgi_server_cfg *base = (scgi_server_cfg *) basev;
scgi_server_cfg *overrides = (scgi_server_cfg *) overridesv;
c->mounts = apr_array_append(p, overrides->mounts, base->mounts);
c->timeout = MERGE(base, overrides, timeout);
return c;
}
static const char *
cmd_mount(cmd_parms *cmd, void *dummy, const char *path, const char *addr)
{
int n;
apr_status_t rv;
char *scope_id = NULL; /* A ip6 parameter - not used here. */
scgi_server_cfg *scfg = our_sconfig(cmd->server);
mount_entry *new = apr_array_push(scfg->mounts);
n = strlen(path);
while (n > 0 && path[n-1] == '/') {
n--; /* strip trailing slashes */
}
new->path = apr_pstrndup(cmd->pool, path, n);
rv = apr_parse_addr_port(&new->addr, &scope_id, &new->port, addr,
cmd->pool);
if (rv)
return "error parsing address:port string";
return NULL;
}
static const char *
cmd_server(cmd_parms *cmd, void *pcfg, const char *addr_and_port)
{
apr_status_t rv;
scgi_cfg *cfg = pcfg;
char *scope_id = NULL; /* A ip6 parameter - not used here. */
if (cmd->path == NULL)
return "not a server command";
rv = apr_parse_addr_port(&cfg->mount.addr, &scope_id, &cfg->mount.port,
addr_and_port, cmd->pool);
if (rv)
return "error parsing address:port string";
return NULL;
}
static const char *
cmd_handler(cmd_parms* cmd, void* pcfg, int flag)
{
scgi_cfg *cfg = pcfg;
if (cmd->path == NULL) /* server command */
return "not a server command";
if (flag)
cfg->enabled = ENABLED;
else
cfg->enabled = DISABLED;
return NULL;
}
static const char *
cmd_timeout(cmd_parms *cmd, void* pcfg, const char *strtimeout)
{
scgi_cfg *dcfg = pcfg;
int timeout = atoi(strtimeout);
if (cmd->path == NULL) {
scgi_server_cfg *scfg = our_sconfig(cmd->server);
scfg->timeout = timeout;
}
else {
dcfg->timeout = timeout;
}
return NULL;
}
static const command_rec scgi_cmds[] =
{
AP_INIT_TAKE2("SCGIMount", cmd_mount, NULL, RSRC_CONF,
"path prefix and address of SCGI server"),
AP_INIT_TAKE1("SCGIServer", cmd_server, NULL, ACCESS_CONF,
"Address and port of an SCGI server (e.g. localhost:4000)"),
AP_INIT_FLAG( "SCGIHandler", cmd_handler, NULL, ACCESS_CONF,
"On or Off to enable or disable the SCGI handler"),
AP_INIT_TAKE1("SCGIServerTimeout", cmd_timeout, NULL, ACCESS_CONF|RSRC_CONF,
"Timeout (in seconds) for communication with the SCGI server."),
{NULL}
};
static void scgi_register_hooks(apr_pool_t *p)
{
ap_hook_post_config(scgi_init, NULL, NULL, APR_HOOK_MIDDLE);
ap_hook_handler(scgi_handler, NULL, NULL, APR_HOOK_MIDDLE);
ap_hook_translate_name(scgi_translate, NULL, NULL, APR_HOOK_LAST);
ap_hook_map_to_storage(scgi_map_location, NULL, NULL, APR_HOOK_FIRST);
}
/* Dispatch list for API hooks */
module AP_MODULE_DECLARE_DATA scgi_module = {
STANDARD20_MODULE_STUFF,
create_dir_config, /* create per-dir config structs */
merge_dir_config, /* merge per-dir config structs */
create_server_config, /* create per-server config structs */
merge_server_config, /* merge per-server config structs */
scgi_cmds, /* table of config file commands */
scgi_register_hooks, /* register hooks */
};
UPDATE to the UPDATE:
I have narrowed down the problem to the following Error Message MCH3601:
MCH3601 Escape 40 06/05/15 15:41:10.884937 MOD_SCGI QGPL *STMT MOD_SCGI QGPL *STMT
From module . . . . . . . . : MOD_SCGI
From procedure . . . . . . : our_dconfig
Statement . . . . . . . . . : 1
To module . . . . . . . . . : MOD_SCGI
To procedure . . . . . . . : our_dconfig
Statement . . . . . . . . . : 1
Thread . . . . : 00000039
Message . . . . : Pointer not set for location referenced.
Cause . . . . . : A pointer was used, either directly or as a basing
pointer, that has not been set to an address.
It looks like the web server is actually Apache, not WAS. What does the Apache log say?
Is the Apache user profile authorised to the mod_scgi service program, and to the library QGPL?
I have a buffer overflow vulnerability in a simple webserver. It can be exploited with a http GET request. I'm having trouble figuring out how to fix it. My guess is that it has to do with: char hdrval[1024]; but I could be wrong. Can anyone else see whats wrong?
Code:
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <stdlib.h>
#include <netdb.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <fcntl.h>
#include <time.h>
#include <pthread.h>
#define _XOPEN_SOURCE
typedef struct {
char *method;
char *uri;
char *version;
char *headers;
} httpreq_t;
/* NOTE: this function is based on a function provided in the GNU "timegm" man
page. timegm is a GNU extension to time.h that returns the given tm struct as
a UNIX timestamp in GMT/UTC, rather than local time. The man page suggests a
function similar to the one below as a portable equivalent.
*/
time_t my_timegm(struct tm *tm) {
time_t ret;
char *tz;
tz = getenv("TZ");
putenv("TZ=GMT");
tzset();
ret = mktime(tm);
if (tz) {
char envstr[strlen(tz) + 4];
envstr[0] = '\0';
strcat(envstr, "TZ=");
strcat(envstr, tz);
putenv(envstr);
} else {
putenv("TZ=");
}
tzset();
return ret;
}
char *get_header(const httpreq_t *req, const char* headername) {
char *hdrptr;
char *hdrend;
char *retval = NULL;
char searchstr[strlen(headername) + 5];
strcpy(searchstr, "\r\n");
strcat(searchstr, headername);
strcat(searchstr, ": ");
if (hdrptr = strstr(req->headers, searchstr)) {
hdrptr += strlen(searchstr);
if (hdrend = strstr(hdrptr, "\r\n")) {
char hdrval[1024]; // temporary return value
memcpy((char *)hdrval, hdrptr, (hdrend - hdrptr));
hdrval[hdrend - hdrptr] = '\0'; // tack null onto end of header value
int hdrvallen = strlen(hdrval);
retval = (char *)malloc((hdrvallen + 1) * sizeof(char)); // malloc a space for retval
strcpy(retval, (char *)hdrval);
} else {
retval = (char *)malloc((strlen(hdrptr) + 1) * sizeof(char)); //
strcpy(retval, hdrptr);
}
}
return retval;
}
/* As long as str begins with a proper HTTP-Version followed by delim, returns a
pointer to the start of the version number (e.g., 1.0). Returns NULL otherwise.
*/
char *http_version_str(char *str, char *delim) {
char *vstart = strstr(str, "HTTP/");
char *vnumstart = str + 5;
char *vdot = strchr(str, '.');
char *vend = strstr(str, delim);
char *digits = "0123456789";
int majvlen = 0;
int minvlen = 0;
if (!vstart || !vdot // something's missing
|| vstart != str) // str doesn't start with "HTTP/"
return NULL;
majvlen = strspn(vnumstart, digits);
minvlen = strspn(vdot + 1, digits);
if (majvlen < 1 || (vnumstart + majvlen) != vdot // bad major version
|| minvlen < 1 || (vdot + minvlen + 1) != vend) // bad minor version
return NULL;
return vnumstart;
}
/* Fills req with the request data from datastr. Returns 0 on success.
*/
int parsereq(httpreq_t *req, char *datastr) {
char *position;
char *last_position = datastr;
char *temp_position;
int matchlen;
req->method = "";
req->uri = "";
req->version = "";
req->headers = "";
if (!(position = strchr(last_position, ' '))) {
return 1;
}
matchlen = (int)(position - last_position);
req->method = (char *)malloc((matchlen + 1) * sizeof(char));
memcpy(req->method, last_position, matchlen);
req->method[matchlen] = '\0';
last_position = position + 1;
if (!(position = strchr(last_position, ' '))
&& !(position = strstr(last_position, "\r\n"))) {
return 1;
}
// strip any query string out of the URI
if ((temp_position = strchr(last_position, '?')) && temp_position < position)
matchlen = (int)(temp_position - last_position);
else
matchlen = (int)(position - last_position);
req->uri = (char *)malloc((matchlen + 1) * sizeof(char));
memcpy(req->uri, last_position, matchlen);
req->uri[matchlen] = '\0';
if (position[0] == '\r') {
req->version = "0.9";
req->headers = "";
return 0; // simple req -- uri only
}
// If we get here, it's a full request, get the HTTP version and headers
last_position = position + 1;
if (!(position = strstr(last_position, "\r\n"))
|| !(last_position = http_version_str(last_position, "\r\n"))) {
return 1;
}
matchlen = (int)(position - last_position);
req->version = (char *)malloc((matchlen + 1) * sizeof(char));
memcpy(req->version, last_position, matchlen);
req->version[matchlen] = '\0';
last_position = position;
req->headers = (char *)malloc(strlen(last_position) * sizeof(char));
strcpy(req->headers, last_position);
return 0;
}
char *contype(char *ext) {
if (strcmp(ext, "html") == 0) return "text/html";
else if (strcmp(ext, "htm") == 0) return "text/html";
else if (strcmp(ext, "jpeg") == 0) return "image/jpeg";
else if (strcmp(ext, "jpg") == 0) return "image/jpeg";
else if (strcmp(ext, "gif") == 0) return "image/gif";
else if (strcmp(ext, "txt") == 0) return "text/plain";
else return "application/octet-stream";
}
char *status(int statcode) {
if (statcode == 200) return "200 OK";
else if (statcode == 304) return "304 Not Modified";
else if (statcode == 400) return "400 Bad Request";
else if (statcode == 403) return "403 Forbidden";
else if (statcode == 404) return "404 Not Found";
else if (statcode == 500) return "500 Internal Server Error";
else if (statcode == 501) return "501 Not Implemented";
else return "";
}
int send_response(int sockfd, httpreq_t *req, int statcode) {
int urifd;
const int BUFSIZE = 1024;
char sendmessage[BUFSIZE];
char *path = req->uri;
if (req->uri == NULL || req->method == NULL ||
req->headers == NULL || req->version == NULL) {
return 0;
}
if ((path[0] == '/') || ((strstr(path, "http://") == path)
&& (path = strchr(path + 7, '/')))) {
path += 1; // remove leading slash
if (path[0] == '\0') { // substituting in index.html for a blank URL!
path = "index.html";
} else if (path[strlen(path) - 1] == '/') {
//concatenating index.html for a /-terminated URL!
strcat(path, "index.html");
}
} else {
statcode = 400;
}
if (statcode == 200 && (urifd = open(path, O_RDONLY, 0)) < 0) {
if (errno == ENOENT || errno == ENOTDIR) { // file or directory doesn't exist
statcode = 404;
} else if (errno == EACCES) { // access denied
statcode = 403;
} else {
// some other file access problem
statcode = 500;
}
}
if (strstr(path, "..") != NULL) {
statcode = 500;
}
sendmessage[0] = '\0';
if (strcmp(req->version, "0.9") != 0) { // full request
char *ext; // file extension
time_t curtime;
char *imstime;
struct tm tm;
struct stat stbuf;
if (statcode == 200) {
if (ext = strrchr(path, '.')) ext++; // skip the '.'
else ext = "";
} else {
// errors are always html messages
ext = "html";
}
// Conditional GET
if ((strcmp(req->method, "GET") == 0)
&& (statcode == 200)
&& (imstime = get_header(req, "If-Modified-Since"))) {
// Get statistics about the requested URI from the local filesystem
if (stat(path, &stbuf) == -1) {
statcode = 500;
}
if (!strptime(imstime, "%a, %d %b %Y %H:%M:%S GMT", &tm)
&& !strptime(imstime, "%a, %d-%b-%y %H:%M:%S GMT", &tm)
&& !strptime(imstime, "%a %b %d %H:%M:%S %Y", &tm)) {
// badly formatted date
statcode = 400;
}
if (stbuf.st_mtime <= my_timegm(&tm)) {
// Not Modified
statcode = 304;
}
}
time(&curtime); // time for Date: header
strcat(sendmessage, "HTTP/1.0 ");
strcat(sendmessage, status(statcode));
strcat(sendmessage, "\r\nDate: ");
strncat(sendmessage, asctime(gmtime(&curtime)), 24);
strcat(sendmessage, "\r\nServer: Frobozz Magic Software Company Webserver v.002");
strcat(sendmessage, "\r\nConnection: close");
strcat(sendmessage, "\r\nContent-Type: ");
strcat(sendmessage, contype(ext));
strcat(sendmessage, "\r\n\r\n");
}
if (statcode != 200) {
strcat(sendmessage, "<html><head><title>");
strcat(sendmessage, status(statcode));
strcat(sendmessage, "</title></head><body><h2>HTTP/1.0</h2><h1>");
strcat(sendmessage, status(statcode));
strcat(sendmessage, "</h1><h2>URI: ");
strcat(sendmessage, path);
strcat(sendmessage, "</h2></body></html>");
}
if (sendmessage[0] != '\0') {
// send headers as long as there are headers to send
if (send(sockfd, sendmessage, strlen(sendmessage), 0) < 0) {
perror("send");
pthread_exit(NULL);
}
}
if (statcode == 200 && (strcmp(req->method, "HEAD") != 0)) {
// send the requested file as long as there's no error and the
// request wasn't just for the headers
int readbytes;
while (readbytes = read(urifd, sendmessage, BUFSIZE)) {
if (readbytes < 0) {
perror("read");
pthread_exit(NULL);
}
if (send(sockfd, sendmessage, readbytes, 0) < 0) {
perror("send");
pthread_exit(NULL);
}
}
}
}
void *data_thread(void *sockfd_ptr) {
int sockfd = *(int *) sockfd_ptr;
const int BUFSIZE = 5;
char recvmessage[BUFSIZE];
char *headerstr = NULL;
char *newheaderstr = NULL;
int recvbytes = 0;
int curheadlen = 0;
int totalheadlen = 0;
httpreq_t req;
int statcode = 200;
int done = 0;
int seen_header = 0;
char *header_end;
int content_length = 0;
char *qstr;
free(sockfd_ptr); // we have the int value out of this now
recvmessage[BUFSIZE - 1] = '\0'; // mark end of "string"
/* Read incoming client message from the socket */
while(!done && (recvbytes = recv(sockfd, recvmessage, BUFSIZE - 1, 0))) {
if (recvbytes < 0) {
perror("recv");
pthread_exit(NULL);
}
recvmessage[recvbytes] = '\0';
if (seen_header) {
// getting the entity body
content_length -= recvbytes;
if (content_length <= 0) done = 1;
} else {
newheaderstr = (char *) malloc((totalheadlen + recvbytes + 1) * sizeof(char));
newheaderstr[totalheadlen + recvbytes] = '\0';
memcpy(newheaderstr, headerstr, totalheadlen);
memcpy(newheaderstr + totalheadlen, recvmessage, recvbytes);
if (headerstr) free(headerstr);
headerstr = newheaderstr;
totalheadlen += recvbytes;
header_end = strstr(headerstr, "\r\n\r\n");
if (header_end) {
seen_header = 1;
header_end[2] = '\0';
if (parsereq(&req, headerstr) != 0) {
statcode = 400;
}
if (strcmp(req.method, "POST") == 0) {
// grab the body length
char *clenstr = get_header(&req, "Content-Length");
if (clenstr) {
content_length = atoi(clenstr) - ((headerstr + totalheadlen) - header_end - 4);
if (content_length <= 0) done = 1;
free(clenstr);
} else {
statcode = 400; // bad request -- no content length
done = 1;
}
} else {
// This isn't a POST, so there's no entity body
done = 1;
if (strcmp(req.method, "GET") != 0
&& strcmp(req.method, "HEAD") != 0) {
statcode = 501; // unknown request method
}
}
}
}
} // end of recv while loop
// used to deref a NULL pointer here... :(
if (headerstr != NULL) {
printf("%s\n", headerstr);
free(headerstr);
}
send_response(sockfd, &req, statcode);
close(sockfd);
return NULL;
}
int main(int argc, char *argv[]) {
int acc, sockfd, clen, port;
struct hostent *he;
struct sockaddr_in caddr, saddr;
if(argc <= 1) {
fprintf(stderr, "No port specified. Exiting!\n");
exit(1);
}
port = atoi(argv[1]);
/* Obtain name and address for the local host */
if((he=gethostbyname("localhost"))==NULL) {
herror("gethostbyname");
exit(1);
}
/* Open a TCP (Internet Stream) socket */
if((sockfd=socket(AF_INET,SOCK_STREAM,0)) == -1) {
perror("socket");
exit(1);
}
/* Create socket address structure for the local host */
memset((char *) &saddr, '\0', sizeof(saddr));
saddr.sin_family=AF_INET;
saddr.sin_port=htons(port);
saddr.sin_addr.s_addr=htonl(INADDR_ANY);
/* Bind our local address so that the client can send to us */
if(bind(sockfd,(struct sockaddr *) &saddr,sizeof(saddr)) == -1) {
perror("bind");
exit(1);
}
if(listen(sockfd,5) < 0) {
perror("listen");
exit(1);
}
/* Infinite loop for receiving and processing client requests */
for(;;) {
clen=sizeof(caddr);
/* Wait for a connection for a client process */
acc=accept(sockfd,(struct sockaddr *) &caddr,(socklen_t*)&clen);
if(acc < 0) {
perror("accept");
exit(1);
} else {
pthread_t *thread = (pthread_t *) malloc(sizeof(pthread_t));
int *sockfd_ptr = (int *) malloc(sizeof(int));
*sockfd_ptr = acc;
pthread_create(thread, NULL, data_thread, sockfd_ptr);
}
}
return 0;
}
I guess you could have a bound check before copying to the buffer?
For example, add
if(hdrend - hdrptr >= 1024)
exit(1)
before
memcpy((char *)hdrval, hdrptr, (hdrend - hdrptr));
The segfault happens at the point below.
Program received signal SIGSEGV, Segmentation fault.
[Switching to Thread 0xb7ff4b70 (LWP 3902)]
Program received signal SIGSEGV, Segmentation fault.
[Switching to Thread 0xb7ff4b70 (LWP 3902)]
0x08049507 in send_response (sockfd=6, req=0xb7ff4340, statcode=200)
at server/webserver.c:219
warning: Source file is more recent than executable.
219 if (req->uri == NULL || req->method == NULL ||
The memory address is
(gdb) p $_siginfo._sifields._sigfault.si_addr
$3 = (void *) 0x69cb120
The code that needs to be rewritten is
214 int urifd;
215 const int BUFSIZE = 1024;
216 char sendmessage[BUFSIZE];
217 char *path = req->uri;
218
219 if (req->uri == NULL || req->method == NULL ||
220 req->headers == NULL || req->version == NULL) {
221 return 0;