acl/lib_acl/samples/master/single_proxy/single_proxy.c

395 lines
10 KiB
C
Raw Normal View History

2014-11-19 00:25:21 +08:00
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include "lib_acl.h"
#include "single_proxy.h"
int var_proxy_log_level;
int var_proxy_tmout;
int var_proxy_connect_tmout;
int var_proxy_rw_tmout;
int var_proxy_bufsize;
int var_proxy_retries;
char *var_proxy_banner;
char *var_proxy_backend_addr;
char *var_proxy_in_file;
char *var_proxy_out_file;
char *var_proxy_host_allow;
static ACL_CONFIG_INT_TABLE __conf_int_tab[] = {
{ VAR_PROXY_LOG_LEVEL, DEF_PROXY_LOG_LEVEL, &var_proxy_log_level, 0, 0 },
{ VAR_PROXY_TMOUT, DEF_PROXY_TMOUT, &var_proxy_tmout, 0, 0 },
{ VAR_PROXY_CONNECT_TMOUT, DEF_PROXY_CONNECT_TMOUT, &var_proxy_connect_tmout, 0, 0 },
{ VAR_PROXY_RW_TMOUT, DEF_PROXY_RW_TMOUT, &var_proxy_rw_tmout, 0, 0 },
{ VAR_PROXY_BUFSIZE, DEF_PROXY_BUFSIZE, &var_proxy_bufsize, 0, 0 },
{ VAR_PROXY_RETRIES, DEF_PROXY_RETRIES, &var_proxy_retries, 0, 0},
{ 0, 0, 0, 0, 0 },
};
static ACL_CONFIG_STR_TABLE __conf_str_tab[] = {
{ VAR_PROXY_BANNER, DEF_PROXY_BANNER, &var_proxy_banner },
{ VAR_PROXY_BACKEND_ADDR, DEF_PROXY_BACKEND_ADDR, &var_proxy_backend_addr },
{ VAR_PROXY_IN_FILE, DEF_PROXY_IN_FILE, &var_proxy_in_file },
{ VAR_PROXY_OUT_FILE, DEF_PROXY_OUT_FILE, &var_proxy_out_file },
{ VAR_PROXY_HOST_ALLOW, DEF_PROXY_HOST_ALLOW, &var_proxy_host_allow },
{ 0, 0, 0 },
};
static ACL_EVENT *__eventp = NULL;
static ACL_VSTREAM *__front_stream = NULL;
static ACL_VSTREAM *__backend_stream = NULL;
static ACL_IPLINK *__host_allow_link = NULL;
/* forward define */
static int __if_host_allow(const char *client_ip);
static void __proxy_handle_fn(int type acl_unused, ACL_EVENT *event acl_unused,
ACL_VSTREAM *stream, void *context)
{
const char *myname = "__proxy_handle_fn";
char buf[8192];
int n, ret;
#undef OVER_RETURN
#define OVER_RETURN do { \
acl_event_disable_readwrite(__eventp, __backend_stream); \
acl_vstream_close(__backend_stream); \
__backend_stream = NULL; \
return; \
} while (0);
if (context == NULL) {
acl_msg_error("%s(%d)->%s: input error, null context",
__FILE__, __LINE__, myname);
return;
}
if (stream == __front_stream) {
n = acl_vstream_read(stream, buf, sizeof(buf) - 1);
if (n == ACL_VSTREAM_EOF) {
if(var_proxy_log_level > 3)
acl_msg_info("%s(%d)->%s: read over",
__FILE__, __LINE__, myname);
OVER_RETURN;
}
ret = acl_vstream_writen(__backend_stream, buf, n);
if (ret != n) {
if(var_proxy_log_level > 3)
acl_msg_info("%s(%d)->%s: write error = %s",
__FILE__, __LINE__, myname,
strerror(errno));
OVER_RETURN;
}
} else if (stream == __backend_stream) {
n = acl_vstream_read(stream, buf, sizeof(buf) - 1);
if (n == ACL_VSTREAM_EOF) {
if(var_proxy_log_level > 3)
acl_msg_info("%s(%d)->%s: read over",
__FILE__, __LINE__, myname);
OVER_RETURN;
}
ret = acl_vstream_writen(__front_stream, buf, n);
if (ret != n) {
if(var_proxy_log_level > 3)
acl_msg_info("%s(%d)->%s: write error = %s",
__FILE__, __LINE__, myname,
strerror(errno));
OVER_RETURN;
}
}
}
2017-07-05 00:01:22 +08:00
static void __service(void *ctx acl_unused, ACL_VSTREAM *stream)
2014-11-19 00:25:21 +08:00
{
const char *myname = "__service";
char buf[64];
int connect_retries = var_proxy_retries;
__front_stream = stream;
if (var_proxy_log_level > 3)
2017-07-05 00:01:22 +08:00
acl_msg_info("%s(%d)->%s: rw_timeout = %d",
__FILE__, __LINE__, myname, stream->rw_timeout);
2014-11-19 00:25:21 +08:00
(void) acl_getpeername(ACL_VSTREAM_SOCK(__front_stream),
buf, sizeof(buf));
acl_vstream_set_peer(__front_stream, buf);
if (__if_host_allow(buf) < 0)
return;
if (var_proxy_log_level > 2)
acl_msg_info("%s(%d)->%s: connected from addr=%s",
__FILE__, __LINE__, myname,
ACL_VSTREAM_PEER(__front_stream));
while (connect_retries) {
__backend_stream =
acl_vstream_connect(var_proxy_backend_addr,
ACL_BLOCKING,
var_proxy_connect_tmout,
var_proxy_rw_tmout,
var_proxy_bufsize);
if (__backend_stream != NULL)
break;
acl_msg_warn("%s(%d)->%s: can't connect server = %s,"
" serr = %s",
__FILE__, __LINE__, myname,
var_proxy_backend_addr, strerror(errno));
connect_retries--;
}
if (__backend_stream == NULL) {
acl_msg_error("%s(%d)->%s: can't connect server=%s, retries=%d",
__FILE__, __LINE__, myname,
var_proxy_backend_addr, var_proxy_retries);
return;
}
if (var_proxy_log_level > 2)
acl_msg_info("%s(%d)->%s: ok, connect ip=%s, retries=%d",
__FILE__, __LINE__, myname,
ACL_VSTREAM_PEER(__backend_stream),
var_proxy_retries - connect_retries);
acl_event_enable_read(__eventp,
__front_stream,
0,
__proxy_handle_fn,
__front_stream);
acl_event_enable_read(__eventp,
__backend_stream,
0,
__proxy_handle_fn,
__backend_stream);
while (1) {
acl_watchdog_pat();
acl_event_loop(__eventp);
if (__backend_stream == NULL)
break;
}
acl_event_disable_readwrite(__eventp, __front_stream);
__front_stream = NULL;
}
static void __add_one_host_item(ACL_IPLINK *allow_link, const char *pitem)
{
char myname[] = "__add_one_host_item";
char *pdata = NULL;
char *from, *to, *ptr;
#undef RETURN
#define RETURN do { \
if (pdata != NULL) \
acl_myfree(pdata); \
return; \
} while (0);
if (pitem == NULL || *pitem == 0) {
acl_msg_error("%s(%d)->%s: pitem invalid",
__FILE__, __LINE__, myname);
RETURN;
}
pdata = acl_mystrdup(pitem);
from = pdata;
/* skip when: '[' || ',' || ' ' || '\t' */
while (*from == '[' || *from == ',' || *from == ' ' || *from == '\t')
from++;
if (*from == 0) {
acl_msg_error("%s(%d)->%s: invalid item: %s",
__FILE__, __LINE__, myname,
pitem);
RETURN;
}
ptr = from;
/* the "from" end with: ' ' || '\t' || ',' */
while (*ptr) {
if (*ptr == ' ' || *ptr == '\t' || *ptr == ',') {
*ptr++ = 0;
break;
}
ptr++;
}
if (*from == 0) {
acl_msg_error("%s(%d)->%s: invalid item: %s",
__FILE__, __LINE__, myname,
pitem);
RETURN;
}
/* skip when: ' ' || '\t' || ',' */
while (*ptr == ' ' || *ptr == '\t' || *ptr == ',')
ptr++;
if (*ptr == 0) {
acl_msg_error("%s(%d)->%s: invalid item: %s",
__FILE__, __LINE__, myname,
pitem);
RETURN;
}
to = ptr;
/* the "to" end with: ' ' || '\t' || ',' || ']' */
while (*ptr) {
if (*ptr == ' ' || *ptr == '\t' || *ptr == ',' || *ptr == ']') {
*ptr = 0;
break;
}
ptr++;
}
if (*to == 0) {
acl_msg_error("%s(%d)->%s: invalid item: %s",
__FILE__, __LINE__, myname,
pitem);
RETURN;
}
if (acl_iplink_insert(allow_link, from, to) == NULL) {
acl_msg_error("%s(%d)->%s: call acl_iplink_insert error,"
" invalid item: %s",
__FILE__, __LINE__, myname, pitem);
RETURN;
}
/* else: OK */
if (var_proxy_log_level > 1)
acl_msg_info("%s(%d)->%s: from=%s, to=%s",
__FILE__, __LINE__, myname,
from, to);
RETURN;
}
static void __add_host_allow(const char *host_allow)
{
char myname[] = "__add_host_allow";
char *pdata, *ptr, *pitem;
if (host_allow == NULL)
host_allow = DEF_PROXY_HOST_ALLOW;
pdata = acl_mystrdup(host_allow);
if (pdata == NULL)
acl_msg_fatal("%s(%d)->%s: call acl_mystrdup error=%s",
__FILE__, __LINE__, myname,
strerror(errno));
__host_allow_link = acl_iplink_create(10);
if (__host_allow_link == NULL)
acl_msg_fatal("%s(%d)->%s: call acl_iplink_create error=%s",
__FILE__, __LINE__, myname,
strerror(errno));
ptr = pdata;
while (1) {
pitem = acl_mystrtok(&ptr, "]");
if (pitem == NULL)
break;
__add_one_host_item(__host_allow_link, pitem);
}
acl_myfree(pdata);
}
static int __if_host_allow(const char *client_ip)
{
char myname[] = "__if_host_allow";
if (client_ip == NULL || *client_ip == 0) {
acl_msg_info("%s(%d)->%s: invalid input",
__FILE__, __LINE__, myname);
return (-1);
}
if (__host_allow_link == NULL) {
if (var_proxy_log_level > 3)
acl_msg_info("%s(%d)->%s: host allow, ip=%s",
__FILE__, __LINE__, myname,
client_ip);
return (0);
}
if (acl_iplink_lookup_str(__host_allow_link, client_ip) != NULL) {
if (var_proxy_log_level > 3)
acl_msg_info("%s(%d)->%s: host allow, ip=%s",
__FILE__, __LINE__, myname,
client_ip);
return (0);
}
if (var_proxy_log_level > 3)
acl_msg_warn("%s(%d)->%s: host deny, ip = %s",
__FILE__, __LINE__, myname,
client_ip);
return (-1);
}
static void __pre_jail_init(char *name acl_unused, char **argv acl_unused)
2014-11-19 00:25:21 +08:00
{
char myname[] = "__pre_jail_init";
acl_msg_info("%s(%d)->%s: var_proxy_log_level=%d",
__FILE__, __LINE__, myname, var_proxy_log_level);
acl_msg_info("host-allow:[%s]", var_proxy_host_allow); /* zsx test */
__add_host_allow(var_proxy_host_allow);
if (var_proxy_log_level > 3)
acl_msg_info("%s(%d)->%s: test only",
__FILE__, __LINE__, myname);
if (var_proxy_retries <= 0) {
acl_msg_warn("%s(%d)->%s: proxy_tetries = %d, use default=%d",
__FILE__, __LINE__, myname,
var_proxy_retries, DEF_PROXY_RETRIES);
var_proxy_retries = DEF_PROXY_RETRIES;
}
if (var_proxy_backend_addr == NULL
|| strcmp(var_proxy_backend_addr, DEF_PROXY_BACKEND_ADDR) == 0) {
acl_msg_fatal("%s(%d)->%s: proxy_backend_addr invalid",
__FILE__, __LINE__, myname);
}
__eventp = acl_event_new_select(acl_var_single_delay_sec,
acl_var_single_delay_usec);
if (__eventp == NULL)
acl_msg_fatal("%s(%d)->%s: acl_event_new error",
__FILE__, __LINE__, myname);
}
static void __post_jail_init(char *name acl_unused, char **argv acl_unused)
2014-11-19 00:25:21 +08:00
{
char myname[] = "__post_jail_init";
if (var_proxy_log_level > 3)
acl_msg_info("%s(%d)->%s: test only",
__FILE__, __LINE__, myname);
}
int main(int argc, char *argv[])
{
acl_msg_info("%s: start...", __FILE__);
printf("%s: starting...", __FILE__);
acl_single_server_main(argc, argv, __service,
ACL_MASTER_SERVER_INT_TABLE, __conf_int_tab,
ACL_MASTER_SERVER_STR_TABLE, __conf_str_tab,
ACL_MASTER_SERVER_PRE_INIT, __pre_jail_init,
ACL_MASTER_SERVER_POST_INIT, __post_jail_init,
0);
exit (0);
}