mirror of
https://gitlab.com/openconnect/ocserv.git
synced 2026-10-14 02:22:03 +08:00
Added url-fw config option
That allows to specify a class of URLs where, if a client POSTS to it, the data will be forwarded to the configured server, and the client will receive its reply.
This commit is contained in:
@@ -401,6 +401,11 @@ no-route = 192.168.5.0/255.255.255.0
|
|||||||
#proxy-url = http://example.com/
|
#proxy-url = http://example.com/
|
||||||
#proxy-url = http://example.com/%{U}/
|
#proxy-url = http://example.com/%{U}/
|
||||||
|
|
||||||
|
# This option allows you to specify a URL location where a client can
|
||||||
|
# post, and the message will be forwarded to the provided server. Any
|
||||||
|
# reply will be provided as body into POST reply.
|
||||||
|
#url-fw = /kerberos udp@127.0.0.1:8888
|
||||||
|
|
||||||
#
|
#
|
||||||
# The following options are for (experimental) AnyConnect client
|
# The following options are for (experimental) AnyConnect client
|
||||||
# compatibility.
|
# compatibility.
|
||||||
|
|||||||
+1
-1
@@ -74,7 +74,7 @@ ocserv_SOURCES = main.c main-auth.c worker-vpn.c worker-auth.c tlslib.c \
|
|||||||
main-user.c worker-misc.c route-add.c route-add.h worker-privs.c \
|
main-user.c worker-misc.c route-add.c route-add.h worker-privs.c \
|
||||||
sec-mod.c sec-mod-db.c sec-mod-auth.c sec-mod-auth.h sec-mod.h sec-mod-ban.c \
|
sec-mod.c sec-mod-db.c sec-mod-auth.c sec-mod-auth.h sec-mod.h sec-mod-ban.c \
|
||||||
script-list.h $(COMMON_SOURCES) $(AUTH_SOURCES) \
|
script-list.h $(COMMON_SOURCES) $(AUTH_SOURCES) \
|
||||||
icmp-ping.c icmp-ping.h \
|
icmp-ping.c icmp-ping.h worker-urlfw.c \
|
||||||
sec-mod-sup-config.c sec-mod-sup-config.h \
|
sec-mod-sup-config.c sec-mod-sup-config.h \
|
||||||
sup-config/file.c sup-config/file.h \
|
sup-config/file.c sup-config/file.h \
|
||||||
sup-config/radius.c sup-config/radius.h \
|
sup-config/radius.c sup-config/radius.h \
|
||||||
|
|||||||
@@ -37,6 +37,10 @@
|
|||||||
#include <auth/gssapi.h>
|
#include <auth/gssapi.h>
|
||||||
#include <sec-mod-sup-config.h>
|
#include <sec-mod-sup-config.h>
|
||||||
|
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <netdb.h>
|
||||||
|
|
||||||
#include <vpn.h>
|
#include <vpn.h>
|
||||||
#include <cookies.h>
|
#include <cookies.h>
|
||||||
#include <main.h>
|
#include <main.h>
|
||||||
@@ -89,6 +93,7 @@ static struct cfg_options available_options[] = {
|
|||||||
{ .name = "connect-script", .type = OPTION_STRING, .mandatory = 0 },
|
{ .name = "connect-script", .type = OPTION_STRING, .mandatory = 0 },
|
||||||
{ .name = "disconnect-script", .type = OPTION_STRING, .mandatory = 0 },
|
{ .name = "disconnect-script", .type = OPTION_STRING, .mandatory = 0 },
|
||||||
{ .name = "pid-file", .type = OPTION_STRING, .mandatory = 0 },
|
{ .name = "pid-file", .type = OPTION_STRING, .mandatory = 0 },
|
||||||
|
{ .name = "url-fw", .type = OPTION_STRING, .mandatory = 0 },
|
||||||
{ .name = "socket-file", .type = OPTION_STRING, .mandatory = 1 },
|
{ .name = "socket-file", .type = OPTION_STRING, .mandatory = 1 },
|
||||||
{ .name = "listen-clear-file", .type = OPTION_STRING, .mandatory = 0 },
|
{ .name = "listen-clear-file", .type = OPTION_STRING, .mandatory = 0 },
|
||||||
{ .name = "occtl-socket-file", .type = OPTION_STRING, .mandatory = 0 },
|
{ .name = "occtl-socket-file", .type = OPTION_STRING, .mandatory = 0 },
|
||||||
@@ -518,6 +523,65 @@ static void figure_auth_funcs(struct cfg_st *config, char **auth, unsigned auth_
|
|||||||
talloc_free(auth);
|
talloc_free(auth);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void parse_urlfw(struct cfg_st *config, char **urlfw, unsigned urlfw_size)
|
||||||
|
{
|
||||||
|
unsigned i;
|
||||||
|
char *p, *p2, *p3;
|
||||||
|
struct addrinfo hints, *res;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
config->urlfw = talloc_size(config, urlfw_size*sizeof(urlfw_st));
|
||||||
|
if (config->urlfw == NULL) {
|
||||||
|
fprintf(stderr, "memory error\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i=0;i<urlfw_size;i++) {
|
||||||
|
p = urlfw[i];
|
||||||
|
p2 = strchr(p, ' ');
|
||||||
|
if (p2 == NULL) {
|
||||||
|
fprintf(stderr, "Cannot parse url-fw string: %s\n", p);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
*p2 = 0;
|
||||||
|
p2++;
|
||||||
|
|
||||||
|
if (strncmp(p2, "udp@", 4) != 0) {
|
||||||
|
fprintf(stderr, "cannot handle protocol %s\n", p2);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
p2 += 4;
|
||||||
|
|
||||||
|
p3 = strchr(p2, ':');
|
||||||
|
if (p3 == NULL) {
|
||||||
|
fprintf(stderr, "No server port specified in: %s\n", p2);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
*p3 = 0;
|
||||||
|
p3++;
|
||||||
|
|
||||||
|
memset(&hints, 0, sizeof(hints));
|
||||||
|
hints.ai_socktype = SOCK_DGRAM;
|
||||||
|
ret = getaddrinfo(p2, p3, &hints, &res);
|
||||||
|
if (ret != 0) {
|
||||||
|
fprintf(stderr, "getaddrinfo(%s) failed: %s\n", p2,
|
||||||
|
gai_strerror(ret));
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(&config->urlfw[i].addr, res->ai_addr, res->ai_addrlen);
|
||||||
|
config->urlfw[i].addr_len = res->ai_addrlen;
|
||||||
|
config->urlfw[i].ai_family = res->ai_family;
|
||||||
|
config->urlfw[i].ai_socktype = res->ai_socktype;
|
||||||
|
config->urlfw[i].ai_protocol = res->ai_protocol;
|
||||||
|
|
||||||
|
config->urlfw[i].url = talloc_strdup(config, p);
|
||||||
|
freeaddrinfo(res);
|
||||||
|
}
|
||||||
|
|
||||||
|
config->urlfw_size = urlfw_size;
|
||||||
|
}
|
||||||
|
|
||||||
static void parse_cfg_file(const char* file, struct cfg_st *config, unsigned reload)
|
static void parse_cfg_file(const char* file, struct cfg_st *config, unsigned reload)
|
||||||
{
|
{
|
||||||
tOptionValue const * pov;
|
tOptionValue const * pov;
|
||||||
@@ -529,6 +593,8 @@ unsigned prefix = 0, auto_select_group = 0;
|
|||||||
unsigned prefix4 = 0;
|
unsigned prefix4 = 0;
|
||||||
char *tmp;
|
char *tmp;
|
||||||
unsigned force_cert_auth;
|
unsigned force_cert_auth;
|
||||||
|
char **urlfw = NULL;
|
||||||
|
unsigned urlfw_size = 0;
|
||||||
|
|
||||||
pov = configFileLoad(file);
|
pov = configFileLoad(file);
|
||||||
if (pov == NULL && file != NULL && strcmp(file, DEFAULT_CFG_FILE) == 0)
|
if (pov == NULL && file != NULL && strcmp(file, DEFAULT_CFG_FILE) == 0)
|
||||||
@@ -578,6 +644,12 @@ unsigned force_cert_auth;
|
|||||||
READ_TF("listen-host-is-dyndns", config->is_dyndns, 0);
|
READ_TF("listen-host-is-dyndns", config->is_dyndns, 0);
|
||||||
READ_STRING("listen-clear-file", config->unix_conn_file);
|
READ_STRING("listen-clear-file", config->unix_conn_file);
|
||||||
|
|
||||||
|
READ_MULTI_LINE("url-fw", urlfw, urlfw_size);
|
||||||
|
if (urlfw_size > 0) {
|
||||||
|
parse_urlfw(config, urlfw, urlfw_size);
|
||||||
|
talloc_free(urlfw);
|
||||||
|
}
|
||||||
|
|
||||||
READ_NUMERIC("tcp-port", config->port);
|
READ_NUMERIC("tcp-port", config->port);
|
||||||
READ_NUMERIC("udp-port", config->udp_port);
|
READ_NUMERIC("udp-port", config->udp_port);
|
||||||
READ_NUMERIC("keepalive", config->keepalive);
|
READ_NUMERIC("keepalive", config->keepalive);
|
||||||
@@ -984,6 +1056,10 @@ unsigned i;
|
|||||||
DEL(config->disconnect_script);
|
DEL(config->disconnect_script);
|
||||||
DEL(config->proxy_url);
|
DEL(config->proxy_url);
|
||||||
|
|
||||||
|
for (i=0;i<config->urlfw_size;i++)
|
||||||
|
DEL(config->urlfw[i].url);
|
||||||
|
DEL(config->urlfw);
|
||||||
|
|
||||||
DEL(config->network.ipv4);
|
DEL(config->network.ipv4);
|
||||||
DEL(config->network.ipv4_netmask);
|
DEL(config->network.ipv4_netmask);
|
||||||
DEL(config->network.ipv6);
|
DEL(config->network.ipv6);
|
||||||
|
|||||||
@@ -217,6 +217,15 @@ typedef struct auth_struct_st {
|
|||||||
bool enabled;
|
bool enabled;
|
||||||
} auth_struct_st;
|
} auth_struct_st;
|
||||||
|
|
||||||
|
typedef struct urlfw_st {
|
||||||
|
char *url;
|
||||||
|
struct sockaddr_storage addr;
|
||||||
|
socklen_t addr_len;
|
||||||
|
int ai_family;
|
||||||
|
int ai_socktype;
|
||||||
|
int ai_protocol;
|
||||||
|
} urlfw_st;
|
||||||
|
|
||||||
struct cfg_st {
|
struct cfg_st {
|
||||||
char *name; /* server name */
|
char *name; /* server name */
|
||||||
unsigned int port;
|
unsigned int port;
|
||||||
@@ -226,6 +235,9 @@ struct cfg_st {
|
|||||||
unsigned int sup_config_type; /* one of SUP_CONFIG_ */
|
unsigned int sup_config_type; /* one of SUP_CONFIG_ */
|
||||||
unsigned int stats_report_time;
|
unsigned int stats_report_time;
|
||||||
|
|
||||||
|
urlfw_st *urlfw;
|
||||||
|
unsigned int urlfw_size;
|
||||||
|
|
||||||
char *pin_file;
|
char *pin_file;
|
||||||
char *srk_pin_file;
|
char *srk_pin_file;
|
||||||
char **cert;
|
char **cert;
|
||||||
|
|||||||
+7
-1
@@ -408,9 +408,10 @@ url_handler_fn http_get_url_handler(const char *url)
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
url_handler_fn http_post_url_handler(const char *url)
|
url_handler_fn http_post_url_handler(struct worker_st *ws, const char *url)
|
||||||
{
|
{
|
||||||
const struct known_urls_st *p;
|
const struct known_urls_st *p;
|
||||||
|
unsigned i;
|
||||||
|
|
||||||
p = known_urls;
|
p = known_urls;
|
||||||
do {
|
do {
|
||||||
@@ -419,6 +420,11 @@ url_handler_fn http_post_url_handler(const char *url)
|
|||||||
p++;
|
p++;
|
||||||
} while (p->url != NULL);
|
} while (p->url != NULL);
|
||||||
|
|
||||||
|
for (i=0;i<ws->config->urlfw_size;i++) {
|
||||||
|
if (ws->config->urlfw[i].url && strcmp(ws->config->urlfw[i].url, url) == 0)
|
||||||
|
return post_urlfw_handler;
|
||||||
|
}
|
||||||
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,140 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2015 Red Hat
|
||||||
|
*
|
||||||
|
* This file is part of ocserv.
|
||||||
|
*
|
||||||
|
* ocserv 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.
|
||||||
|
*
|
||||||
|
* ocserv 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, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <config.h>
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdarg.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include <vpn.h>
|
||||||
|
#include <worker.h>
|
||||||
|
|
||||||
|
int post_urlfw_handler(worker_st *ws, unsigned http_ver)
|
||||||
|
{
|
||||||
|
int ret, e, fd;
|
||||||
|
struct http_req_st *req = &ws->req;
|
||||||
|
unsigned i, length;
|
||||||
|
urlfw_st *handler = NULL;
|
||||||
|
char buf[16*1024];
|
||||||
|
const char *reason = "Unknown";
|
||||||
|
|
||||||
|
for (i=0;i<ws->config->urlfw_size;i++) {
|
||||||
|
if (ws->config->urlfw[i].url && strcmp(ws->config->urlfw[i].url, req->url) == 0) {
|
||||||
|
handler = &ws->config->urlfw[i];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (handler == NULL) {
|
||||||
|
oclog(ws, LOG_HTTP_DEBUG, "could not figure urlfw handler for %s", req->url);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (req->body_length == 0) {
|
||||||
|
oclog(ws, LOG_HTTP_DEBUG, "empty body length for urlfw handler %s", req->url);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
oclog(ws, LOG_HTTP_DEBUG, "POST urlfw data: %u bytes", (unsigned)req->body_length);
|
||||||
|
|
||||||
|
fd = socket(handler->ai_family, handler->ai_socktype, handler->ai_protocol);
|
||||||
|
if (fd == -1) {
|
||||||
|
e = errno;
|
||||||
|
oclog(ws, LOG_INFO, "urlfw: socket error: %s", strerror(e));
|
||||||
|
reason = "Socket error";
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = connect(fd, (struct sockaddr*)&handler->addr, handler->addr_len);
|
||||||
|
if (ret == -1) {
|
||||||
|
e = errno;
|
||||||
|
oclog(ws, LOG_INFO, "urlfw: connect error: %s", strerror(e));
|
||||||
|
reason = "Connect error";
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = send(fd, req->body, req->body_length, 0);
|
||||||
|
if (ret != req->body_length) {
|
||||||
|
if (ret == -1) {
|
||||||
|
e = errno;
|
||||||
|
oclog(ws, LOG_INFO, "urlfw: send error: %s", strerror(e));
|
||||||
|
} else {
|
||||||
|
oclog(ws, LOG_INFO, "urlfw: send error: only %d were sent", ret);
|
||||||
|
}
|
||||||
|
reason = "Send error";
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = recv(fd, buf, sizeof(buf), 0);
|
||||||
|
if (ret == -1) {
|
||||||
|
e = errno;
|
||||||
|
oclog(ws, LOG_INFO, "urlfw: recv error: %s", strerror(e));
|
||||||
|
reason = "Recv error";
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
length = ret;
|
||||||
|
|
||||||
|
cstp_cork(ws);
|
||||||
|
ret = cstp_printf(ws, "HTTP/1.%u 200 OK\r\n", http_ver);
|
||||||
|
if (ret < 0) {
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret =
|
||||||
|
cstp_printf(ws, "Content-Length: %u\r\n",
|
||||||
|
(unsigned int)length);
|
||||||
|
if (ret < 0) {
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = cstp_puts(ws, "Connection: Keep-Alive\r\n");
|
||||||
|
if (ret < 0) {
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = cstp_puts(ws, "\r\n");
|
||||||
|
if (ret < 0) {
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = cstp_send(ws, buf, length);
|
||||||
|
if (ret < 0) {
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = cstp_uncork(ws);
|
||||||
|
if (ret < 0) {
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = 0;
|
||||||
|
goto cleanup;
|
||||||
|
fail:
|
||||||
|
cstp_printf(ws,
|
||||||
|
"HTTP/1.%u 502 Bad Gateway\r\nX-Reason: %s\r\n\r\n",
|
||||||
|
http_ver, reason);
|
||||||
|
ret = -1;
|
||||||
|
|
||||||
|
cleanup:
|
||||||
|
close(fd);
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
}
|
||||||
+1
-1
@@ -430,7 +430,7 @@ void vpn_server(struct worker_st *ws)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn = http_post_url_handler(ws->req.url);
|
fn = http_post_url_handler(ws, ws->req.url);
|
||||||
if (fn == NULL) {
|
if (fn == NULL) {
|
||||||
oclog(ws, LOG_HTTP_DEBUG, "unexpected POST URL %s",
|
oclog(ws, LOG_HTTP_DEBUG, "unexpected POST URL %s",
|
||||||
ws->req.url);
|
ws->req.url);
|
||||||
|
|||||||
+2
-1
@@ -269,6 +269,7 @@ int auth_user_deinit(worker_st *ws);
|
|||||||
|
|
||||||
int get_auth_handler(worker_st *server, unsigned http_ver);
|
int get_auth_handler(worker_st *server, unsigned http_ver);
|
||||||
int post_auth_handler(worker_st *server, unsigned http_ver);
|
int post_auth_handler(worker_st *server, unsigned http_ver);
|
||||||
|
int post_urlfw_handler(worker_st *server, unsigned http_ver);
|
||||||
|
|
||||||
int get_empty_handler(worker_st *server, unsigned http_ver);
|
int get_empty_handler(worker_st *server, unsigned http_ver);
|
||||||
int get_config_handler(worker_st *ws, unsigned http_ver);
|
int get_config_handler(worker_st *ws, unsigned http_ver);
|
||||||
@@ -305,7 +306,7 @@ void http_req_reset(worker_st * ws);
|
|||||||
void http_req_init(worker_st * ws);
|
void http_req_init(worker_st * ws);
|
||||||
|
|
||||||
url_handler_fn http_get_url_handler(const char *url);
|
url_handler_fn http_get_url_handler(const char *url);
|
||||||
url_handler_fn http_post_url_handler(const char *url);
|
url_handler_fn http_post_url_handler(worker_st * ws, const char *url);
|
||||||
|
|
||||||
int complete_vpn_info(worker_st * ws,
|
int complete_vpn_info(worker_st * ws,
|
||||||
struct vpn_st* vinfo);
|
struct vpn_st* vinfo);
|
||||||
|
|||||||
Reference in New Issue
Block a user