Nilorea Library
C utilities for networking, threading, graphics
Loading...
Searching...
No Matches
ex_network_proxy.c
Go to the documentation of this file.
1/*
2 * Nilorea Library
3 * Copyright (C) 2005-2026 Castagnier Mickael
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
14 * implied. See the License for the specific language governing
15 * permissions and limitations under the License.
16 *
17 * SPDX-License-Identifier: Apache-2.0
18 */
19
28#include "nilorea/n_common.h"
29#include "nilorea/n_log.h"
30#include "nilorea/n_network.h"
31
32#include <stdio.h>
33#include <string.h>
34#ifndef __windows__
35#include <sys/socket.h>
36#include <unistd.h>
37#endif
38
39int main(int argc, char* argv[]) {
40 int errors = 0;
41
42 /* parse log level from -V flag if present */
43 int log_level = LOG_INFO;
44 for (int i = 1; i < argc; i++) {
45 if (strcmp(argv[i], "-V") == 0 && i + 1 < argc) {
46 if (strcmp(argv[i + 1], "LOG_DEBUG") == 0)
48 else if (strcmp(argv[i + 1], "LOG_ERR") == 0)
50 else if (strcmp(argv[i + 1], "LOG_NOTICE") == 0)
52 }
53 }
55
56 n_log(LOG_INFO, "ex_network_proxy: proxy URL parser demo");
57
58 /* Test 1: authenticated HTTP proxy */
59 {
60 N_PROXY_CFG* cfg = n_proxy_cfg_parse("http://user:pass@proxy.corp:3128");
61 if (cfg) {
62 n_log(LOG_INFO, " scheme=%s host=%s port=%d user=%s pass=%s",
63 cfg->scheme, cfg->host, cfg->port,
64 cfg->username ? cfg->username : "(null)",
65 cfg->password ? cfg->password : "(null)");
66 if (strcmp(cfg->scheme, "http") != 0) errors++;
67 if (strcmp(cfg->host, "proxy.corp") != 0) errors++;
68 if (cfg->port != 3128) errors++;
69 if (!cfg->username || strcmp(cfg->username, "user") != 0) errors++;
70 if (!cfg->password || strcmp(cfg->password, "pass") != 0) errors++;
71 n_proxy_cfg_free(&cfg);
72 } else {
73 n_log(LOG_ERR, " FAIL: parse returned NULL");
74 errors++;
75 }
76 }
77
78 /* Test 2: unauthenticated SOCKS5 proxy */
79 {
80 N_PROXY_CFG* cfg = n_proxy_cfg_parse("socks5://proxy.corp:1080");
81 if (cfg) {
82 n_log(LOG_INFO, " scheme=%s host=%s port=%d user=%s",
83 cfg->scheme, cfg->host, cfg->port,
84 cfg->username ? cfg->username : "(null)");
85 if (strcmp(cfg->scheme, "socks5") != 0) errors++;
86 if (strcmp(cfg->host, "proxy.corp") != 0) errors++;
87 if (cfg->port != 1080) errors++;
88 if (cfg->username != NULL) errors++;
89 n_proxy_cfg_free(&cfg);
90 } else {
91 n_log(LOG_ERR, " FAIL: parse returned NULL");
92 errors++;
93 }
94 }
95
96 /* Test 3: authenticated HTTPS proxy */
97 {
98 N_PROXY_CFG* cfg = n_proxy_cfg_parse("https://admin:secret@secure-proxy.corp:8443");
99 if (cfg) {
100 n_log(LOG_INFO, " scheme=%s host=%s port=%d user=%s pass=%s",
101 cfg->scheme, cfg->host, cfg->port,
102 cfg->username ? cfg->username : "(null)",
103 cfg->password ? cfg->password : "(null)");
104 if (strcmp(cfg->scheme, "https") != 0) errors++;
105 if (strcmp(cfg->host, "secure-proxy.corp") != 0) errors++;
106 if (cfg->port != 8443) errors++;
107 if (!cfg->username || strcmp(cfg->username, "admin") != 0) errors++;
108 if (!cfg->password || strcmp(cfg->password, "secret") != 0) errors++;
109 n_proxy_cfg_free(&cfg);
110 } else {
111 n_log(LOG_ERR, " FAIL: parse returned NULL");
112 errors++;
113 }
114 }
115
116 /* Test 4: HTTPS proxy with default port */
117 {
118 N_PROXY_CFG* cfg = n_proxy_cfg_parse("https://secure-proxy.corp");
119 if (cfg) {
120 n_log(LOG_INFO, " scheme=%s host=%s port=%d",
121 cfg->scheme, cfg->host, cfg->port);
122 if (strcmp(cfg->scheme, "https") != 0) errors++;
123 if (cfg->port != 3128) errors++;
124 n_proxy_cfg_free(&cfg);
125 } else {
126 n_log(LOG_ERR, " FAIL: parse returned NULL");
127 errors++;
128 }
129 }
130
131 /* Test 5: invalid URL */
132 {
133 N_PROXY_CFG* cfg = n_proxy_cfg_parse("not-a-url");
134 if (cfg) {
135 n_log(LOG_ERR, " FAIL: expected NULL for invalid URL");
136 n_proxy_cfg_free(&cfg);
137 errors++;
138 } else {
139 n_log(LOG_INFO, " invalid URL correctly returned NULL");
140 }
141 }
142
143 /* Test 6: adopt an already-connected socket fd into a client NETWORK and
144 * round-trip raw bytes over its plain send/recv vtable. A socketpair stands
145 * in for the fd a proxy CONNECT tunnel would return. POSIX-only: Winsock has
146 * no socketpair()/AF_UNIX equivalent. */
147#ifndef __windows__
148 {
149 int sv[2];
150 if (socketpair(AF_UNIX, SOCK_STREAM, 0, sv) != 0) {
151 n_log(LOG_ERR, " FAIL: socketpair failed");
152 errors++;
153 } else {
154 NETWORK* netw = NULL;
155 if (netw_adopt_client_fd(&netw, (SOCKET)sv[0], "tunnel.target", "443") == TRUE && netw) {
156 char rbuf[8];
157 /* peer -> NETWORK */
158 if (send(sv[1], "PING", 4, 0) != 4) errors++;
159 memset(rbuf, 0, sizeof(rbuf));
160 if (netw->recv_data(netw, rbuf, 4) != 4 || memcmp(rbuf, "PING", 4) != 0) {
161 n_log(LOG_ERR, " FAIL: adopted recv mismatch");
162 errors++;
163 }
164 /* NETWORK -> peer */
165 if (netw->send_data(netw, "PONG", 4) != 4) errors++;
166 memset(rbuf, 0, sizeof(rbuf));
167 if (recv(sv[1], rbuf, 4, 0) != 4 || memcmp(rbuf, "PONG", 4) != 0) {
168 n_log(LOG_ERR, " FAIL: adopted send mismatch");
169 errors++;
170 }
171 if (errors == 0)
172 n_log(LOG_INFO, " adopted fd round-trip OK");
173 netw_close(&netw); /* closes sv[0] */
174 } else {
175 n_log(LOG_ERR, " FAIL: netw_adopt_client_fd returned FALSE");
176 errors++;
177 closesocket(sv[0]);
178 }
179 closesocket(sv[1]);
180 }
181 }
182#endif /* !__windows__ */
183
184 /* Test 7: netw_adopt_client_fd rejects a non-empty target and a bad fd. */
185 {
186 NETWORK* netw = NULL;
187 if (netw_adopt_client_fd(&netw, INVALID_SOCKET, "h", "1") != FALSE) {
188 n_log(LOG_ERR, " FAIL: expected FALSE for INVALID_SOCKET");
189 errors++;
190 } else {
191 n_log(LOG_INFO, " invalid fd correctly returned FALSE");
192 }
193 }
194
195 n_log(LOG_INFO, "ex_network_proxy: %s (%d error%s)",
196 errors == 0 ? "PASS" : "FAIL", errors, errors == 1 ? "" : "s");
197 return errors > 0 ? 1 : 0;
198}
int main(void)
int log_level
Definition ex_fluid.c:60
NETWORK * netw
Network for server mode, accepting incomming.
Definition ex_network.c:39
#define n_log(__LEVEL__,...)
Logging function wrapper to get line and func.
Definition n_log.h:89
#define LOG_DEBUG
debug-level messages
Definition n_log.h:84
#define LOG_ERR
error conditions
Definition n_log.h:76
void set_log_level(const int log_level)
Set the global log level value ( static int LOG_LEVEL )
Definition n_log.c:121
#define LOG_NOTICE
normal but significant condition
Definition n_log.h:80
#define LOG_INFO
informational
Definition n_log.h:82
char * host
proxy hostname
Definition n_network.h:815
char * password
NULL if no auth.
Definition n_network.h:818
int port
proxy port
Definition n_network.h:816
char * scheme
"http", "https", or "socks5"
Definition n_network.h:814
netw_func send_data
send func ptr
Definition n_network.h:359
char * username
NULL if no auth.
Definition n_network.h:817
netw_func recv_data
receive func ptr
Definition n_network.h:361
N_PROXY_CFG * n_proxy_cfg_parse(const char *url)
Parse a proxy URL string into an N_PROXY_CFG struct.
Definition n_network.c:7597
int netw_adopt_client_fd(NETWORK **netw, SOCKET fd, const char *host, const char *port)
Adopt an already-connected socket fd into a fresh client NETWORK.
Definition n_network.c:8040
int SOCKET
default socket declaration
Definition n_network.h:102
void n_proxy_cfg_free(N_PROXY_CFG **cfg)
Free an N_PROXY_CFG created by n_proxy_cfg_parse().
Definition n_network.c:7692
int netw_close(NETWORK **netw)
Closing a specified Network, destroy queues, free the structure.
Definition n_network.c:2662
Parsed proxy URL components.
Definition n_network.h:813
Structure of a NETWORK.
Definition n_network.h:309
Common headers and low-level functions & define.
Generic log system.
Network Engine.