File: proxyprotocol.c

package info (click to toggle)
tlswrapper 0~20230101-1
  • links: PTS, VCS
  • area: main
  • in suites: bookworm
  • size: 1,784 kB
  • sloc: ansic: 7,085; sh: 2,247; makefile: 220
file content (162 lines) | stat: -rw-r--r-- 4,606 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
/*
20211119
Jan Mojzis
Public domain.
*/

#include <unistd.h>
#include <string.h>
#include "e.h"
#include "log.h"
#include "str.h"
#include "buffer.h"
#include "stralloc.h"
#include "jail.h"
#include "iptostr.h"
#include "strtoip.h"
#include "strtoport.h"
#include "porttostr.h"
#include "proxyprotocol.h"

int proxyprotocol_v1_get(int fd, unsigned char *localipx,
                         unsigned char *localportx, unsigned char *remoteipx,
                         unsigned char *remoteportx) {

    buffer sin = buffer_INIT(buffer_read, fd, /*no buffer*/ 0, /*no buffer*/ 0);
    int ret = 0;
    long long pos;
    char bufspace[PROXYPROTOCOL_MAX];
    char buforig[PROXYPROTOCOL_MAX];
    char *buf = bufspace;
    int (*strtoipop)(unsigned char *, const char *);
    unsigned char localip[16] = {0};
    unsigned char localport[2] = {0};
    unsigned char remoteip[16] = {0};
    unsigned char remoteport[2] = {0};

    log_t1("proxyprotocol_v1_get()");

    /* read proxy string byte-by-byte */
    for (pos = 0; pos < PROXYPROTOCOL_MAX - 1; ++pos) {
        if (buffer_GETC(&sin, &buf[pos]) != 1) {
            log_e1("unable to read proxy-protocol string");
            goto cleanup;
        }
        if (buf[pos] == '\n') break;
    }
    if (buf[pos] != '\n') {
        errno = EPROTO;
        log_e1("unable to read proxy-protocol string, no CRLF");
        goto cleanup;
    }
    /*if (pos > 0 && buf[pos - 1] == '\r') --pos; */
    buf[pos + 1] = 0;
    memcpy(buforig, bufspace, PROXYPROTOCOL_MAX);

    /* header */
    if (str_start(buf, "PROXY UNKNOWN")) {
        ret = 1;
        goto cleanup;
    }
    else if (str_start(buf, "PROXY TCP4 ")) {
        strtoipop = strtoip4;
    }
    else if (str_start(buf, "PROXY TCP6 ")) {
        strtoipop = strtoip6;
    }
    else {
        log_e3("unable to parse proxy-protocol string '", buforig, "'");
        goto cleanup;
    }
    buf += 11;

    /* remote ip */
    pos = str_chr(buf, ' ');
    buf[pos] = 0;
    if (!strtoipop(remoteip, buf)) {
        log_e3("unable to parse remoteip from proxy-protocol string '", buforig,
               "'");
        goto cleanup;
    }
    buf += pos + 1;

    /* localip ip */
    pos = str_chr(buf, ' ');
    buf[pos] = 0;
    if (!strtoipop(localip, buf)) {
        log_e3("unable to parse localip from proxy-protocol string '", buforig,
               "'");
        goto cleanup;
    }
    buf += pos + 1;

    /* remote port */
    pos = str_chr(buf, ' ');
    buf[pos] = 0;
    if (!strtoport(remoteport, buf)) {
        log_e3("unable to parse remoteport from proxy-protocol string '",
               buforig, "'");
        goto cleanup;
    }
    buf += pos + 1;

    /* localport */
    buf[str_chr(buf, '\n')] = 0;
    buf[str_chr(buf, '\r')] = 0;
    if (!strtoport(localport, buf)) {
        log_e3("unable to parse localport from proxy-protocol string '",
               buforig, "'");
        goto cleanup;
    }

    ret = 1;

cleanup:
    if (ret) {
        memcpy(localipx, localip, 16);
        memcpy(remoteipx, remoteip, 16);
        memcpy(localportx, localport, 2);
        memcpy(remoteportx, remoteport, 2);
    }
    log_t2("proxyprotocol_v1_get() = ", lognum(ret));
    return ret;
}

long long proxyprotocol_v1(char *buf, long long buflen, unsigned char *localip,
                           unsigned char *localport, unsigned char *remoteip,
                           unsigned char *remoteport) {

    stralloc sa = {0};
    long long ret = 0;

    if (!memcmp(localip, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 16) &&
        !memcmp(remoteip, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 16) &&
        !memcmp(localport, "\0\0", 2) && !memcmp(remoteport, "\0\0", 2)) {
        goto cleanup;
    }

    if (!memcmp("\0\0\0\0\0\0\0\0\0\0\377\377", remoteip, 12)) {
        if (!stralloc_copys(&sa, "PROXY TCP4 ")) goto cleanup;
    }
    else {
        if (!stralloc_copys(&sa, "PROXY TCP6 ")) goto cleanup;
    }
    if (!stralloc_cats(&sa, iptostr(0, remoteip))) goto cleanup;
    if (!stralloc_cats(&sa, " ")) goto cleanup;
    if (!stralloc_cats(&sa, iptostr(0, localip))) goto cleanup;
    if (!stralloc_cats(&sa, " ")) goto cleanup;
    if (!stralloc_cats(&sa, porttostr(0, remoteport))) goto cleanup;
    if (!stralloc_cats(&sa, " ")) goto cleanup;
    if (!stralloc_cats(&sa, porttostr(0, localport))) goto cleanup;
    if (!stralloc_cats(&sa, "\r\n")) goto cleanup;
    if (!stralloc_0(&sa)) goto cleanup;
    --sa.len;
    if (buf && buflen >= sa.len) {
        memcpy(buf, sa.s, sa.len);
        ret = sa.len;
    }

cleanup:
    stralloc_free(&sa);
    return ret;
}