Willy Tarreau | c14b7d9 | 2014-06-19 16:03:41 +0200 | [diff] [blame] | 1 | 2013/10/10 - possibilities for setting source and destination addresses |
| 2 | |
| 3 | |
| 4 | When establishing a connection to a remote device, this device is designated |
| 5 | as a target, which designates an entity defined in the configuration. A same |
| 6 | target appears only once in a configuration, and multiple targets may share |
| 7 | the same settings if needed. |
| 8 | |
| 9 | The following types of targets are currently supported : |
| 10 | |
| 11 | - listener : all connections with this type of target come from clients ; |
| 12 | - server : connections to such targets are for "server" lines ; |
| 13 | - peer : connections to such target address "peer" lines in "peers" |
| 14 | sections ; |
| 15 | - proxy : these targets are used by "dispatch", "option transparent" |
| 16 | or "option http_proxy" statements. |
| 17 | |
| 18 | A connection might not be reused between two different targets, even if all |
| 19 | parameters seem similar. One of the reason is that some parameters are specific |
| 20 | to the target and are not easy or not cheap to compare (eg: bind to interface, |
| 21 | mss, ...). |
| 22 | |
| 23 | A number of source and destination addresses may be set for a given target. |
| 24 | |
| 25 | - listener : |
| 26 | - the "from" address:port is set by accept() |
| 27 | |
| 28 | - the "to" address:port is set if conn_get_to_addr() is called |
| 29 | |
| 30 | - peer : |
| 31 | - the "from" address:port is not set |
| 32 | |
| 33 | - the "to" address:port is static and dependent only on the peer |
| 34 | |
| 35 | - server : |
| 36 | - the "from" address may be set alone when "source" is used with |
| 37 | a forced IP address, or when "usesrc clientip" is used. |
| 38 | |
| 39 | - the "from" port may be set only combined with the address when |
| 40 | "source" is used with IP:port, IP:port-range or "usesrc client" is |
| 41 | used. Note that in this case, both the address and the port may be |
| 42 | 0, meaning that the kernel will pick the address or port and that |
| 43 | the final value might not match the one explicitly set (eg: |
| 44 | important for logging). |
| 45 | |
| 46 | - the "from" address may be forced from a header which implies it |
| 47 | may change between two consecutive requests on the same connection. |
| 48 | |
| 49 | - the "to" address and port are set together when connecting to a |
| 50 | regular server, or by copying the client's IP address when |
| 51 | "server 0.0.0.0" is used. Note that the destination port may be |
| 52 | an offset applied to the original destination port. |
| 53 | |
| 54 | - proxy : |
| 55 | - the "from" address may be set alone when "source" is used with a |
| 56 | forced IP address or when "usesrc clientip" is used. |
| 57 | |
| 58 | - the "from" port may be set only combined with the address when |
| 59 | "source" is used with IP:port or with "usesrc client". There is |
| 60 | no ip:port range for a proxy as of now. Same comment applies as |
| 61 | above when port and/or address are 0. |
| 62 | |
| 63 | - the "from" address may be forced from a header which implies it |
| 64 | may change between two consecutive requests on the same connection. |
| 65 | |
| 66 | - the "to" address and port are set together, either by configuration |
| 67 | when "dispatch" is used, or dynamically when "transparent" is used |
| 68 | (1:1 with client connection) or "option http_proxy" is used, where |
| 69 | each client request may lead to a different destination address. |
| 70 | |
| 71 | |
| 72 | At the moment, there are some limits in what might happen between multiple |
| 73 | concurrent requests to a same target. |
| 74 | |
| 75 | - peers parameter do not change, so no problem. |
| 76 | |
| 77 | - server parameters may change in this way : |
| 78 | - a connection may require a source bound to an IP address found in a |
| 79 | header, which will fall back to the "source" settings if the address |
| 80 | is not found in this header. This means that the source address may |
| 81 | switch between a dynamically forced IP address and another forced |
| 82 | IP and/or port range. |
| 83 | |
| 84 | - if the element is not found (eg: header), the remaining "forced" |
| 85 | source address might very well be empty (unset), so the connection |
| 86 | reuse is acceptable when switching in that direction. |
| 87 | |
| 88 | - it is not possible to switch between client and clientip or any of |
| 89 | these and hdr_ip() because they're exclusive. |
| 90 | |
| 91 | - using a source address/port belonging to a port range is compatible |
| 92 | with connection reuse because there is a single range per target, so |
| 93 | switching from a range to another range means we remain in the same |
| 94 | range. |
| 95 | |
| 96 | - destination address may currently not change since the only possible |
| 97 | case for dynamic destination address setting is the transparent mode, |
| 98 | reproducing the client's destination address. |
| 99 | |
| 100 | - proxy parameters may change in this way : |
| 101 | - a connection may require a source bound to an IP address found in a |
| 102 | header, which will fall back to the "source" settings if the address |
| 103 | is not found in this header. This means that the source address may |
| 104 | switch between a dynamically forced IP address and another forced |
| 105 | IP and/or port range. |
| 106 | |
| 107 | - if the element is not found (eg: header), the remaining "forced" |
| 108 | source address might very well be empty (unset), so the connection |
| 109 | reuse is acceptable when switching in that direction. |
| 110 | |
| 111 | - it is not possible to switch between client and clientip or any of |
| 112 | these and hdr_ip() because they're exclusive. |
| 113 | |
| 114 | - proxies do not support port ranges at the moment. |
| 115 | |
| 116 | - destination address might change in the case where "option http_proxy" |
| 117 | is used. |
| 118 | |
| 119 | So, for each source element (IP, port), we want to know : |
| 120 | - if the element was assigned by static configuration (eg: ":80") |
| 121 | - if the element was assigned from a connection-specific value (eg: usesrc clientip) |
| 122 | - if the element was assigned from a configuration-specific range (eg: 1024-65535) |
| 123 | - if the element was assigned from a request-specific value (eg: hdr_ip(xff)) |
| 124 | - if the element was not assigned at all |
| 125 | |
| 126 | For the destination, we want to know : |
| 127 | - if the element was assigned by static configuration (eg: ":80") |
| 128 | - if the element was assigned from a connection-specific value (eg: transparent) |
| 129 | - if the element was assigned from a request-specific value (eg: http_proxy) |
| 130 | |
| 131 | We don't need to store the information about the origin of the dynamic value |
| 132 | since we have the value itself. So in practice we have : |
| 133 | - default value, unknown (not yet checked with getsockname/getpeername) |
| 134 | - default value, known (check done) |
| 135 | - forced value (known) |
| 136 | - forced range (known) |
| 137 | |
| 138 | We can't do that on an ip:port basis because the port may be fixed regardless |
| 139 | of the address and conversely. |
| 140 | |
| 141 | So that means : |
| 142 | |
| 143 | enum { |
| 144 | CO_ADDR_NONE = 0, /* not set, unknown value */ |
| 145 | CO_ADDR_KNOWN = 1, /* not set, known value */ |
| 146 | CO_ADDR_FIXED = 2, /* fixed value, known */ |
| 147 | CO_ADDR_RANGE = 3, /* from assigned range, known */ |
| 148 | } conn_addr_values; |
| 149 | |
| 150 | unsigned int new_l3_src_status:2; |
| 151 | unsigned int new_l4_src_status:2; |
| 152 | unsigned int new_l3_dst_status:2; |
| 153 | unsigned int new_l4_dst_status:2; |
| 154 | |
| 155 | unsigned int cur_l3_src_status:2; |
| 156 | unsigned int cur_l4_src_status:2; |
| 157 | unsigned int cur_l3_dsp_status:2; |
| 158 | unsigned int cur_l4_dst_status:2; |
| 159 | |
| 160 | unsigned int new_family:2; |
| 161 | unsigned int cur_family:2; |
| 162 | |
| 163 | Note: this obsoletes CO_FL_ADDR_FROM_SET and CO_FL_ADDR_TO_SET. These flags |
| 164 | must be changed to individual l3+l4 checks ORed between old and new values, |
| 165 | or better, set to cur only which will inherit new. |
| 166 | |
| 167 | In the connection, these values may be merged in the same word as err_code. |