use MKSYSERR macro to replace RS_ET_SYS errors
[rofl0r-rocksock.git] / rocksock_add_proxy_fromstring.c
blob959a355753adf7448875fea51fcf9bba0abc00d0
1 #undef _POSIX_C_SOURCE
2 #define _POSIX_C_SOURCE 200809L
3 #undef _GNU_SOURCE
4 #define _GNU_SOURCE
6 #include <string.h>
7 #include <stdlib.h> /* for atoi() */
9 #include "rocksock.h"
10 #include "rocksock_internal.h"
12 #ifndef ROCKSOCK_FILENAME
13 #define ROCKSOCK_FILENAME __FILE__
14 #endif
16 /* valid inputs:
17 socks5://user:password@proxy.domain.com:port
18 socks5://proxy.domain.com:port
19 socks4://proxy.domain.com:port
20 http://user:password@proxy.domain.com:port
21 http://proxy.domain.com:port
23 supplying port number is obligatory.
24 user:pass@ part is optional for http and socks5.
25 however, user:pass authentication is currently not implemented for http proxies.
27 #define MKERR(S, X) rocksock_seterror(S, RS_ET_OWN, X, ROCKSOCK_FILENAME, __LINE__)
28 int rocksock_add_proxy_fromstring(rocksock* sock, const char *proxystring) {
29 if (!sock)
30 return RS_E_NULL;
31 if(!sock->proxies) return MKERR(sock, RS_E_NO_PROXYSTORAGE);
33 const char* p;
34 rs_proxyType proxytype;
35 rs_proxy* prx = &sock->proxies[sock->lastproxy+1];
36 char *user_buf = prx->username;
37 char *pass_buf = prx->password;
38 char *host_buf = prx->hostinfo.host;
39 size_t next_token = 6, ul = 0, pl = 0, hl;
40 if(!proxystring[0] || !proxystring[1] || !proxystring[2] || !proxystring[3] || !proxystring[4] || !proxystring[5]) goto inv_string;
41 if(*proxystring == 's') {
42 switch(proxystring[5]) {
43 case '5': proxytype = RS_PT_SOCKS5; break;
44 case '4': proxytype = RS_PT_SOCKS4; break;
45 default: goto inv_string;
47 } else if(*proxystring == 'h') {
48 proxytype = RS_PT_HTTP;
49 next_token = 4;
50 } else goto inv_string;
51 if(
52 proxystring[next_token++] != ':' ||
53 proxystring[next_token++] != '/' ||
54 proxystring[next_token++] != '/') goto inv_string;
55 const char *at = strchr(proxystring+next_token, '@');
56 if(at) {
57 if(proxytype == RS_PT_SOCKS4)
58 return MKERR(sock, RS_E_SOCKS4_NOAUTH);
59 p = strchr(proxystring+next_token, ':');
60 if(!p || p >= at) goto inv_string;
61 const char *u = proxystring+next_token;
62 ul = p-u;
63 p++;
64 pl = at-p;
65 if(proxytype == RS_PT_SOCKS5 && (ul > 255 || pl > 255))
66 return MKERR(sock, RS_E_SOCKS5_AUTH_EXCEEDSIZE);
67 memcpy(user_buf, u, ul);
68 user_buf[ul]=0;
69 memcpy(pass_buf, p, pl);
70 pass_buf[pl]=0;
71 next_token += 2+ul+pl;
72 } else {
73 user_buf[0]=0;
74 pass_buf[0]=0;
76 const char* h = proxystring+next_token;
77 p = strchr(h, ':');
78 if(!p) goto inv_string;
79 hl = p-h;
80 if(hl > 255)
81 return MKERR(sock, RS_E_HOSTNAME_TOO_LONG);
82 memcpy(host_buf, h, hl);
83 host_buf[hl]=0;
84 sock->lastproxy++;
85 prx->hostinfo.port = atoi(p+1);
86 prx->proxytype = proxytype;
87 return rocksock_seterror(sock, RS_ET_OWN, 0, NULL, 0);
88 inv_string:
89 return MKERR(sock, RS_E_INVALID_PROXY_URL);