[-]
[+]
|
Changed |
haproxy.spec
|
|
[-]
[+]
|
Deleted |
haproxy-1.5-dev26.tar.gz/TODO
^
|
@@ -1,181 +0,0 @@
-* x-forwarded-for
-* implémenter l'option "log global" au niveau proxy pour utiliser les logs
- globaux.
-* matching case-insensitive
-* implémenter outgoing addr
-* loguer t_cnx, t_data, t_total
-+ factoriser la fonction de log (send_log = send_syslog+warning+alert)
-+ désactivation du keep-alive (suppression des ^Connection: et ajout des Connection: close)
- -> 4 lignes (2 del, 2 add) suffisent.
-+ ne pas loguer certaines adresses IP sources
- -> pour les health-checks uniquement -> pas de log pour les requêtes
- vides (option dontlognull)
-- mesurer le tps consommé entre deux select, et fournir la conso CPU :
- %cpu = 100 * (tpreselect(n+1)-tpostselect(n)) / (tpreselect(n+1)-tpreselect(n))
-* implémenter limitation fd dans la conf : setrlimit(RLIMIT_NOFILE, ...)
-- implémenter core/no-core dans la conf : setrlimit(RLIMIT_CORE, ...)
-- optimiser les regex pour accélérer les matches :
- - compter les matches
- - si match(n) & ([n].cpt > [n-1].cpt) & ([n].action == [n-1].action), swap(n,n-1)
- - régulièrement, diviser tous les compteurs (lors d'un dépassement par exemple)
-- filtrage sur l'adresse IP source, et stocker le pointeur sur la dernière regex
- matchée dans la "session" pour accélérer les regex.
-- gestion keep-alive
-
-+ handle parametrable HTTP health-checks replies
-- differentiate http headers and http uris
-- support environment variables in config file
-- support keep-alive
-- support SSL
-
-===================== demandes ==========================
-ok> 1) écoute sur une plage de ports :
-ok> listen XXX 1.2.3.4:21000-21060
-ok>
-ok> 2) écoutes multiples :
-ok> listen XXX 1.2.3.4:21000
-ok> bind 2.3.4.5:21001
-ok> bind 2.3.4.5:21000-21060
-ok>
-ok> => on en arrive à ceci :
-ok>
-ok> listen XXX [ address:port ]
-ok> bind addr:plage-port[,[addr:]plage-port]*
-ok> bind ...
-ok> ...
-ok>
-ok> => proxy->listen_fd et proxy->listen_addr doivent être
-ok> mis dans des listes
-ok> => OK pour listen, implémenter le BIND.
-ok>
-ok> 3) reconnexion sur le même port sur le serveur :
-ok>
-ok> server XXX 1.2.3.4[:port]
-ok> si <port> n'est pas spécifié, on utilise le même port que celui qui a reçu
-ok> la connexion. Dans ce cas, il faut pouvoir forcer le port du health-check
-ok> par un nouveau parametre "port".
-ok>
-ok> => ça permet les forwardings de plages :
-ok>
-ok> listen XXX
-ok> bind 1.2.3.4:10000-11000
-ok> server 1.2.3.5
-ok>
-4) paramètres par défaut :
- créer une section "defaults" qui précise les paramètres par défaut pour les
- sections suivantes, concernant les paramètres suivants :
- ok- les logs
- ok- les modes (tcp/http)
- ok- le balancing (round-robin/source)
- ok- les time-outs
- ok- maxconn
- ok- redisp
- ok- les options
- ok- le retry
- ok- les checks
- ok- les cookies/captures
- - les options des serveurs ?
- - les filtres et regex ?
-
-* implémenter "balance source" pour faire un hash sur la source.
- permettre de spécifier un masque sur lequel s'applique le hachage,
- ainsi qu'une option pour hacher en fonction de l'adresse dans le
- champ "x-forwarded-for". Problème pour le support des pannes: ce
- type de hash est utile là où la persistence par cookie ne peut pas
- s'appliquer, donc comment faire pour assurer un maximum de persistence
- en cas de panne ?
-
-6) possibilité d'un process séparé par listen :
- listen XXX
- fork [ group_id ]
-
- le fait de spécifier group_id fera que toutes les instances utilisant le
- même identifiant de groupe seront gérées par un même processus.
-
- -> plus souple et plus compréhensible de faire des sections par processus,
- ce qui résoud également le cas ci-dessous. Ex:
- process_group X
- nbproc X
- uid X
- chroot X
- listen ...
-
-7) gérer un chroot/uid/gid différents par process :
- listen XXX
- chroot /truc
- uid 123
- gid 456
-
-8) beaucoup de paramètres pourraient être spécifiques aux serveurs et non
- aux instances. Exemples :
- * adresse IP source pour atteindre le serveur
- - méthode de health-check (proto, ...)
- * méthode de health-check (port)
- - poids
- - alerte en cas de disparition
- - le nombre max de sessions à lui envoyer
-
-ok> 9) ajouter des paramètres optionnels à l'option "httpchk" permettant
-ok> de forcer la méthode, la version HTTP et des headers.
-ok> ex: option httpchk -> OPTIONS / HTTP/1.0
-ok> option httpchk /test -> OPTIONS /test HTTP/1.0
-ok> option httpchk HEAD / HTTP/1.0\nHost:\ www -> tel quel
-
-Todo for 1.1
-============
-* "no more server" alert
-* config check
-- anti-flapping
-
-Todo for 1.2
-============
-- direct <server> <regex> <match>
-- new config syntax allowing braces to be able to shorten lines
-- insert/learn/check/log unique request ID, and add the ability
- to block bad responses.
-- IPv6 :
-* listen [ip4.ip4.ip4.ip4]:port[-port]
-* listen [ip6::...ip6]/port[-port]
-- server xxx ipv4 | ipv4: | ipv4:port[-port] | ipv6/ | ipv6/port[-port]
-* appcookie
-* weighted round robin
-- option to shutdown(listen_sock) when max connections reached
-* epoll
-- replace the event scheduler with an O(log(N)) one. The timer queue will
- need a tree with a known end (to speed up queueing of latest events), and
- no entry for eternity.
-- refine memory management so that the request buffer is only allocated in
- cli_read() and response buffer during srv_read(). This would protect against
- attacks with thousands connections : 20000 connections consume 340 MB RSS and
- 1.3 GB VSZ on Linux. Data should be in a separate buffer to prevent any
- activity on the buffer's pointers from touching the buffer page itself.
-- make buffer size configurable in global options
-* monitor number of simultaneous sessions in logs (per srv/inst/global)
-* ignore leading empty lines in HTTP requests
-+ limit the per-server number of sessions and queue incoming connections
- => still needs refinement (actions at servers UP/DOWN, timeouts)
-- new 'timeout' keyword to set all timeouts (including the queue)
-- ability to intercept an URI to report statistics
-- ability to intercept an URI to return 404
-- embedded error pages loaded in memory at startup time (eg: for expired time
- in connection queue)
-
-
-TODO for 1.3
-============
- - check all copyrights
- - fix Makefile.bsd
- - separate inline functions to put them in files covered by GPL
- - implement HTTP status 414 - request URI too long
- - implement 'use_filters <proxy>' and 'use_backend <proxy>'
- - fix the logs. The logs might be defined from the frontend and
- augmented depending on the backends' options. Another solution
- would be to support a 'log' type entity just like the frontend,
- filters and backend, on which every entity could rely.
- - implement 'on uri <uri> <proxy>', 'on host <host> <proxy>'
- - remove the first now useless hop in hdr_idx
- - balance on URI hash (specify length or depth)
- - balance on any header hash (eg: host)
- - balance with redirections to real servers
- - multi-site LB with weighted redirections to the remote one
-
|
[-]
[+]
|
Changed |
haproxy-1.5.3.tar.gz/CHANGELOG
^
|
@@ -1,6 +1,105 @@
ChangeLog :
===========
+2014/07/25 : 1.5.3
+ - DOC: fix typo in Unix Socket commands
+ - BUG/MEDIUM: connection: fix memory corruption when building a proxy v2 header
+ - BUG/MEDIUM: ssl: Fix a memory leak in DHE key exchange
+ - DOC: mention that Squid correctly responds 400 to PPv2 header
+ - BUG/MINOR: http: base32+src should use the big endian version of base32
+ - BUG/MEDIUM: connection: fix proxy v2 header again!
+
+2014/07/12 : 1.5.2
+ - BUG/MEDIUM: backend: Update hash to use unsigned int throughout
+ - BUG/MINOR: ssl: Fix external function in order not to return a pointer on an internal trash buffer.
+ - DOC: expand the docs for the provided stats.
+ - BUG/MEDIUM: unix: do not unlink() abstract namespace sockets upon failure.
+ - MINOR: stats: fix minor typo in HTML page
+ - BUG/MEDIUM: http: fetch "base" is not compatible with set-header
+ - BUG/MINOR: counters: do not untrack counters before logging
+ - BUG/MAJOR: sample: correctly reinitialize sample fetch context before calling sample_process()
+ - MINOR: stick-table: make stktable_fetch_key() indicate why it failed
+ - BUG/MEDIUM: counters: fix track-sc* to wait on unstable contents
+ - BUILD: remove TODO from the spec file and add README
+ - MINOR: log: make MAX_SYSLOG_LEN overridable at build time
+ - MEDIUM: log: support a user-configurable max log line length
+ - DOC: provide an example of how to use ssl_c_sha1
+ - BUILD: http: fix isdigit & isspace warnings on Solaris
+ - BUG/MINOR: listener: set the listener's fd to -1 after deletion
+ - BUG/MEDIUM: unix: failed abstract socket binding is retryable
+ - MEDIUM: listener: implement a per-protocol pause() function
+ - MEDIUM: listener: support rebinding during resume()
+ - BUG/MEDIUM: unix: completely unbind abstract sockets during a pause()
+ - DOC: explicitly mention the limits of abstract namespace sockets
+ - DOC: minor fix on {sc,src}_kbytes_{in,out}
+ - DOC: fix alphabetical sort of converters
+ - BUG/MAJOR: http: correctly rewind the request body after start of forwarding
+ - DOC: remove references to CPU=native in the README
+ - DOC: mention that "compression offload" is ignored in defaults section
+
+2014/06/24 : 1.5.1
+ - BUG/MINOR: config: http-request replace-header arg typo
+ - BUG/MINOR: ssl: rejects OCSP response without nextupdate.
+ - BUG/MEDIUM: ssl: Fix to not serve expired OCSP responses.
+ - BUG/MINOR: ssl: Fix OCSP resp update fails with the same certificate configured twice. (cherry picked from commit 1d3865b096b43b9a6d6a564ffb424ffa6f1ef79f)
+ - BUG/MEDIUM: Consistently use 'check' in process_chk
+ - BUG/MAJOR: session: revert all the crappy client-side timeout changes
+ - BUG/MINOR: logs: properly initialize and count log sockets
+
+2014/06/19 : 1.5.0
+ - MEDIUM: ssl: ignored file names ending as '.issuer' or '.ocsp'.
+ - MEDIUM: ssl: basic OCSP stapling support.
+ - MINOR: ssl/cli: Fix unapropriate comment in code on 'set ssl ocsp-response'
+ - MEDIUM: ssl: add 300s supported time skew on OCSP response update.
+ - MINOR: checks: mysql-check: Add support for v4.1+ authentication
+ - MEDIUM: ssl: Add the option to use standardized DH parameters >= 1024 bits
+ - MEDIUM: ssl: fix detection of ephemeral diffie-hellman key exchange by using the cipher description.
+ - MEDIUM: http: add actions "replace-header" and "replace-values" in http-req/resp
+ - MEDIUM: Break out check establishment into connect_chk()
+ - MEDIUM: Add port_to_str helper
+ - BUG/MEDIUM: fix ignored values for half-closed timeouts (client-fin and server-fin) in defaults section.
+ - BUG/MEDIUM: Fix unhandled connections problem with systemd daemon mode and SO_REUSEPORT.
+ - MINOR: regex: fix a little configuration memory leak.
+ - MINOR: regex: Create JIT compatible function that return match strings
+ - MEDIUM: regex: replace all standard regex function by own functions
+ - MEDIUM: regex: Remove null terminated strings.
+ - MINOR: regex: Use native PCRE API.
+ - MINOR: missing regex.h include
+ - DOC: Add Exim as Proxy Protocol implementer.
+ - BUILD: don't use type "uint" which is not portable
+ - BUILD: stats: workaround stupid and bogus -Werror=format-security behaviour
+ - BUG/MEDIUM: http: clear CF_READ_NOEXP when preparing a new transaction
+ - CLEANUP: http: don't clear CF_READ_NOEXP twice
+ - DOC: fix proxy protocol v2 decoder example
+ - DOC: fix remaining occurrences of "pattern extraction"
+ - MINOR: log: allow the HTTP status code to be logged even in TCP frontends
+ - MINOR: logs: don't limit HTTP header captures to HTTP frontends
+ - MINOR: sample: improve sample_fetch_string() to report partial contents
+ - MINOR: capture: extend the captures to support non-header keys
+ - MINOR: tcp: prepare support for the "capture" action
+ - MEDIUM: tcp: add a new tcp-request capture directive
+ - MEDIUM: session: allow shorter retry delay if timeout connect is small
+ - MEDIUM: session: don't apply the retry delay when redispatching
+ - MEDIUM: session: redispatch earlier when possible
+ - MINOR: config: warn when tcp-check rules are used without option tcp-check
+ - BUG/MINOR: connection: make proxy protocol v1 support the UNKNOWN protocol
+ - DOC: proxy protocol example parser was still wrong
+ - DOC: minor updates to the proxy protocol doc
+ - CLEANUP: connection: merge proxy proto v2 header and address block
+ - MEDIUM: connection: add support for proxy protocol v2 in accept-proxy
+ - MINOR: tools: add new functions to quote-encode strings
+ - DOC: clarify the CSV format
+ - MEDIUM: stats: report the last check and last agent's output on the CSV status
+ - MINOR: freq_ctr: introduce a new averaging method
+ - MEDIUM: session: maintain per-backend and per-server time statistics
+ - MEDIUM: stats: report per-backend and per-server time stats in HTML and CSV outputs
+ - BUG/MINOR: http: fix typos in previous patch
+ - DOC: remove the ultra-obsolete TODO file
+ - DOC: update roadmap
+ - DOC: minor updates to the README
+ - DOC: mention the maxconn limitations with the select poller
+ - DOC: commit a few old design thoughts files
+
2014/05/28 : 1.5-dev26
- BUG/MEDIUM: polling: fix possible CPU hogging of worker processes after receiving SIGUSR1.
- BUG/MINOR: stats: fix a typo on a closing tag for a server tracking another one
|
[-]
[+]
|
Changed |
haproxy-1.5.3.tar.gz/README
^
|
@@ -1,19 +1,28 @@
----------------------
HAProxy how-to
----------------------
- version 1.5-dev26
+ version 1.5.3
willy tarreau
- 2014/05/28
+ 2014/07/25
1) How to build it
------------------
+First, please note that this version is a stable version, so in general if you
+are not used to build from sources, it is recommended that instead you follow
+the packaged updates provided by your software vendor or Linux distribution.
+Most of them are taking this task seriously and are doing a good job. If for
+any reason you'd prefer a different version than the one packaged for your
+system, or to get some commercial support, other choices are available at :
+
+ http://www.haproxy.com/
+
To build haproxy, you will need :
- GNU make. Neither Solaris nor OpenBSD's make work with the GNU Makefile.
If you get many syntax errors when running "make", you may want to retry
with "gmake" which is the name commonly used for GNU make on BSD systems.
- - GCC between 2.91 and 4.7. Others may work, but not tested.
+ - GCC between 2.95 and 4.8. Others may work, but not tested.
- GNU ld
Also, you might want to build with libpcre support, which will provide a very
@@ -26,15 +35,15 @@
- linux24 for Linux 2.4 and above (default)
- linux24e for Linux 2.4 with support for a working epoll (> 0.21)
- linux26 for Linux 2.6 and above
- - linux2628 for Linux 2.6.28 and above (enables splice and tproxy)
+ - linux2628 for Linux 2.6.28, 3.x, and above (enables splice and tproxy)
- solaris for Solaris 8 or 10 (others untested)
- - freebsd for FreeBSD 5 to 8.0 (others untested)
+ - freebsd for FreeBSD 5 to 10 (others untested)
- osx for Mac OS/X
- openbsd for OpenBSD 3.1 to 5.2 (others untested)
- aix51 for AIX 5.1
- aix52 for AIX 5.2
- cygwin for Cygwin
- - generic for any other OS.
+ - generic for any other OS or version.
- custom to manually adjust every setting
You may also choose your CPU to benefit from some optimizations. This is
@@ -44,8 +53,9 @@
- i686 for intel PentiumPro, Pentium 2 and above, AMD Athlon
- i586 for intel Pentium, AMD K6, VIA C3.
- ultrasparc : Sun UltraSparc I/II/III/IV processor
- - native : use the build machine's specific processor optimizations
- - generic : any other processor or no specific optimization. (default)
+ - native : use the build machine's specific processor optimizations. Use with
+ extreme care, and never in virtualized environments (known to break).
+ - generic : any other processor or no CPU-specific optimization. (default)
Alternatively, you may just set the CPU_CFLAGS value to the optimal GCC options
for your platform.
@@ -123,11 +133,11 @@
And on a classic Linux with SSL and ZLIB support (eg: Red Hat 5.x) :
- $ make TARGET=linux26 CPU=native USE_PCRE=1 USE_OPENSSL=1 USE_ZLIB=1
+ $ make TARGET=linux26 USE_PCRE=1 USE_OPENSSL=1 USE_ZLIB=1
And on a recent Linux >= 2.6.28 with SSL and ZLIB support :
- $ make TARGET=linux2628 CPU=native USE_PCRE=1 USE_OPENSSL=1 USE_ZLIB=1
+ $ make TARGET=linux2628 USE_PCRE=1 USE_OPENSSL=1 USE_ZLIB=1
In order to build a 32-bit binary on an x86_64 Linux system with SSL support
without support for compression but when OpenSSL requires ZLIB anyway :
@@ -177,9 +187,10 @@
AIX 5.3 is known to work with the generic target. However, for the binary to
also run on 5.2 or earlier, you need to build with DEFINE="-D_MSGQSUPPORT",
-otherwise __fd_select() will be used while not being present in the libc.
-If you get build errors because of strange symbols or section mismatches,
-simply remove -g from DEBUG_CFLAGS.
+otherwise __fd_select() will be used while not being present in the libc, but
+this is easily addressed using the "aix52" target. If you get build errors
+because of strange symbols or section mismatches, simply remove -g from
+DEBUG_CFLAGS.
You can easily define your own target with the GNU Makefile. Unknown targets
are processed with no default option except USE_POLL=default. So you can very
@@ -329,16 +340,7 @@
2. if you really can't code it yourself after discussing it, then you may
consider contacting someone to do the job for you. Some people on the
- list might be OK with trying to do it. Otherwise, you can check the list
- of contributors at the URL below, some of the regular contributors may
- be able to do the work, probably not for free but their time is as much
- valuable as yours after all, you can't eat the cake and have it too.
-
-The list of past and regular contributors is available below. It lists not only
-significant code contributions (features, fixes), but also time or money
-donations :
-
- http://www.haproxy.org/contrib.html
+ list might sometimes be OK with trying to do it.
Note to contributors: it's very handy when patches comes with a properly
formated subject. There are 3 criteria of particular importance in any patch :
@@ -526,7 +528,7 @@
definitely help you contribute quality code and take other people's feedback
in consideration. In order to clone the HAProxy Git repository :
- $ git clone http://git.haproxy.org/git/haproxy-1.4.git (stable 1.4)
+ $ git clone http://git.haproxy.org/git/haproxy-1.5.git (stable 1.5)
$ git clone http://git.haproxy.org/git/haproxy.git/ (development)
If you decide to use Git for your developments, then your commit messages will
|
[-]
[+]
|
Changed |
haproxy-1.5.3.tar.gz/ROADMAP
^
|
@@ -1,8 +1,8 @@
-Medium-long term roadmap - 2014/05/10
+Medium-long term roadmap - 2014/06/19
Legend: '+' = done, '-' = todo, '*' = done except doc
-1.5 (ETA 2013/12/31) :
+1.6 or later :
- POST parameter extraction and size/speed measurement to use in ACLs
- return-html code xxx [ file "xxx" | text "xxx" ] if <acl>
@@ -41,113 +41,6 @@
- http-request track-sc* to avoid having the ugly "if !HTTP" in tcp-request
-DONE:
- * half-closed timeouts ?
-
- * add support for server-side unix sockets
-
- * server-side HTTP keepalive
- => maybe with limitation to only reuse connections that don't depend
- on layer7 in a first time (just check the target).
-
- * add support for complex pattern extraction rules :
-
- pattern = <pattern_term>
- | '{' pattern_expr '}'
-
- pattern_expr = <pattern_term> [ <transform> ... ]
- => changed to <sample>[,<conv>]*
-
- * support loading data sets from files
- * present/not present (eg: netmasks)
- * pattern conversion per prefixes. Eg: convert src IP to country.
- => maps
-
- * what to do with data after a POST and how to detect some data were
- received when responding ? In theory we should read everything because
- the TCP stack does not notify us that the FIN was acked. In practice,
- reading just before closing should be enough. Right now we simply read
- whatever comes after the POST.
- => switch the connection to a "drain" state, where it monitors its
- output queue on each I/O and where it can be stolen if fds are
- missing.
-
- * tcp-request {connection|session} expect-proxy {L4|L5} if ...
-
- * rename L4 acls as L6 ACLs when some content is involved
-
- * add new L4 ACL checks immediately after accept, before even allocating the
- buffers ("connection {accept|reject|delay|freeze} {if|unless}").
-
- * make new patterns available based on stickiness matching :
- * number of entries in table for the matched pattern
- * same after having increased the match counter
-
- * add support for concurrency match in tables
- * just like stickiness, but counted per session (or request), increased
- on first match and decreased at end of request or connection. This
- requires that the session has a list of matched terms that must be
- released at the end.
-
- * http_req_first ACL
-
- * expirable cookies + "preserve"
-
- * ECV, LDAPv3 & MySQL checks
-
- * configurable check buffer size
-
- * stats + ON/OFF
-
- * halog: sort by URL
-
- * "PROXY" protocol
-
- * add support for client-side unix sockets
-
- * hash: rehash non-consistent hashes with chash() for more randomness.
-
- * add an error ID in captures to ease new error detection for scripts.
-
- * try to remove srv==NULL internally and assign a dummy server to each backend
- for dispatch, http_proxy and transparent modes. => done differently with the
- target descriptors. The dummy server code exists in the "dummysrv" branch
- which will die since it does not make sense anymore.
-
- * ACL to report number of used entries in a table
-
- * automatically compute fullconn for backends : by default, set it to
- 10% of the sum of the maxconn of all unique frontends which reference
- it via use_backend, default_backend or that are in the same listen.
-
- * count number of monitor requests on frontends, that's the only way
- to explain the possible huge difference between frontend and backend
- sessions.
-
- * assign a nice priority based on ACLs.
-
- * set-log-level if <acl> (front/back)
-
- * fix "PR--" flags when accessing stats
-
- * merged ACL/fetches
-
- * use_server ... if ...
-
- * ability to kill an arbitrary session from the command line. Put a "kill now"
- flag in every session which preempts any other processing and wake the
- session up.
-
- * add a last activity date for each server (req/resp) that will be
- displayed in the stats. It will be useful with soft stop.
-
- * compression : to be fixed
-
- * ACL feeding via the UNIX socket
-
- * lookup tables (eg: map IP to country)
-
-1.6 (will probably change anyway) :
- wait on resource (time, mem, CPU, socket, buffers, server's conn, server's rate, ...)
- bandwidth limits
@@ -174,43 +67,58 @@
to maintenance mode => requires a per-server session list and the change
above.
-Old, maybe obsolete points
- - clarify licence by adding a 'MODULE_LICENCE("GPL")' or something equivalent.
+Old, maybe obsolete points :
+ - clarify licence by adding a 'MODULE_LICENCE("GPL")' or something equivalent.
- - 3 memory models : failsafe (prealloc), normal (current), optimal (alloc on
- demand)
+ - 3 memory models : failsafe (prealloc), normal (current), optimal (alloc on
+ demand)
- - implement support for event-triggerred epoll()
+ - implement support for event-triggerred epoll()
- - verify if it would be worth implementing an epoll_ctl_batch() for Linux
+ - verify if it would be worth implementing an epoll_ctl_batch() for Linux
- - option minservers XXX : activates some spare servers when active servers
- are insufficient
+ - option minservers XXX : activates some spare servers when active servers
+ are insufficient
- - new keyword 'check' : check http xxx, check smtp xxx, check ssl-hello
+ - new keyword 'check' : check http xxx, check smtp xxx, check ssl-hello
- - initcwnd parameter for bind sockets : needed in kernel first
+ - initcwnd parameter for bind sockets : needed in kernel first
- - have a callback function which would be called after a server is selected,
- for header post-processing. That would be mainly used to remove then add
- the server's name or cookie in a header so that the server knows it.
+ - have a callback function which would be called after a server is selected,
+ for header post-processing. That would be mainly used to remove then add
+ the server's name or cookie in a header so that the server knows it.
Unsorted :
- outgoing log load-balancing (round-robin or hash among multiple servers)
+
- internal socket for "server XXX frontend:name"
+
- HTTP/2.0
+
- DNS requests on health checks
+
- XML inspection (content-switching for SOAP requests)
+
- sync all stick-tables data, not just serverid.
+
- request, session and user variables
+
- random cookie generator
+
- external checker
+
- fastcgi to servers
+
- hot config reload
+
- RAM-based cache for small files
+
- RHI - BGP
+
- telnet/SSH cli
+
- dynamic memory allocation
+
- dynamic weights based on check response headers and traffic response time
+
- various kernel-level acceleration (multi-accept, ssplice, epoll2...)
- - "show stats detail" with a different output format and encoding of quotes
|
[-]
[+]
|
Changed |
haproxy-1.5.3.tar.gz/SUBVERS
^
|
@@ -1,2 +1,2 @@
--2e85840
+-$Format:%h$
|
[-]
[+]
|
Changed |
haproxy-1.5.3.tar.gz/VERDATE
^
|
@@ -1,2 +1,2 @@
-2014-05-28 17:50:53 +0200
-2014/05/28
+$Format:%ci$
+2014/07/25
|
[-]
[+]
|
Changed |
haproxy-1.5.3.tar.gz/VERSION
^
|
@@ -1 +1 @@
-1.5-dev26
+1.5.3
|
[-]
[+]
|
Changed |
haproxy-1.5.3.tar.gz/contrib/halog/halog.c
^
|
@@ -694,7 +694,7 @@
struct eb32_node *n;
struct url_stat *ustat = NULL;
int val, test;
- uint uval;
+ unsigned int uval;
int filter_acc_delay = 0, filter_acc_count = 0;
int filter_time_resp = 0;
int filt_http_status_low = 0, filt_http_status_high = 0;
|
[-]
[+]
|
Changed |
haproxy-1.5.3.tar.gz/doc/configuration.txt
^
|
@@ -2,9 +2,9 @@
HAProxy
Configuration Manual
----------------------
- version 1.5
+ version 1.5.3
willy tarreau
- 2014/05/28
+ 2014/07/25
This document covers the configuration language as implemented in the version
@@ -497,6 +497,7 @@
- tune.ssl.lifetime
- tune.ssl.force-private-cache
- tune.ssl.maxrecord
+ - tune.ssl.default-dh-param
- tune.zlib.memlevel
- tune.zlib.windowsize
@@ -558,7 +559,7 @@
Similar to "gid" but uses the GID of group name <group name> from /etc/group.
See also "gid" and "user".
-log <address> <facility> [max level [min level]]
+log <address> [len <length>] <facility> [max level [min level]]
Adds a global syslog server. Up to two global servers can be defined. They
will receive logs for startups and exits, as well as all logs from proxies
configured with "log global".
@@ -583,6 +584,18 @@
optionally enclosing them with braces ('{}'), similarly to what is done
in Bourne shell.
+ <length> is an optional maximum line length. Log lines larger than this value
+ will be truncated before being sent. The reason is that syslog
+ servers act differently on log line length. All servers support the
+ default value of 1024, but some servers simply drop larger lines
+ while others do log them. If a server supports long lines, it may
+ make sense to set this value here in order to avoid truncating long
+ lines. Similarly, if a server drops long lines, it is preferable to
+ truncate them before sending them. Accepted values are 80 to 65535
+ inclusive. The default value of 1024 is generally fine for all
+ standard usages. Some specific cases of long captures or
+ JSON-formated logs may require larger values.
+
<facility> must be one of the 24 standard syslog facilities :
kern user mail daemon auth syslog lpr news
@@ -738,7 +751,11 @@
Sets the maximum per-process number of concurrent connections to <number>. It
is equivalent to the command-line argument "-n". Proxies will stop accepting
connections when this limit is reached. The "ulimit-n" parameter is
- automatically adjusted according to this value. See also "ulimit-n".
+ automatically adjusted according to this value. See also "ulimit-n". Note:
+ the "select" poller cannot reliably use more than 1024 file descriptors on
+ some platforms. If your platform only supports select and reports "select
+ FAILED" on startup, you need to reduce maxconn until it works (slightly
+ below 500 in general).
maxconnrate <number>
Sets the maximum per-process number of connections per second to <number>.
@@ -1017,6 +1034,16 @@
best value. Haproxy will automatically switch to this setting after an idle
stream has been detected (see tune.idletimer above).
+tune.ssl.default-dh-param <number>
+ Sets the maximum size of the Diffie-Hellman parameters used for generating
+ the ephemeral/temporary Diffie-Hellman key in case of DHE key exchange. The
+ final size will try to match the size of the server's RSA (or DSA) key (e.g,
+ a 2048 bits temporary DH key for a 2048 bits RSA key), but will not exceed
+ this maximum value. Default value if 1024. Only 1024 or higher values are
+ allowed. Higher values will increase the CPU load, and values greater than
+ 1024 bits are not supported by Java 7 and earlier clients. This value is not
+ used if static Diffie-Hellman parameters are supplied via the certificate file.
+
tune.zlib.memlevel <number>
Sets the memLevel parameter in zlib initialization for each session. It
defines how much memory should be allocated for the internal compression
@@ -1764,7 +1791,13 @@
- 'ipv4@' -> address is always IPv4
- 'ipv6@' -> address is always IPv6
- 'unix@' -> address is a path to a local unix socket
- - 'abns@' -> address is in abstract namespace (Linux only)
+ - 'abns@' -> address is in abstract namespace (Linux only).
+ Note: since abstract sockets are not "rebindable", they
+ do not cope well with multi-process mode during
+ soft-restart, so it is better to avoid them if
+ nbproc is greater than 1. The effect is that if the
+ new process fails to start, only one of the old ones
+ will be able to rebind to the socket.
- 'fd@<n>' -> use file descriptor <n> inherited from the
parent. The fd must be bound and may or may not already
be listening.
@@ -2116,7 +2149,8 @@
invalid payloads. In this case, simply removing the header in the
configuration does not work because it applies before the header is parsed,
so that prevents haproxy from compressing. The "offload" setting should
- then be used for such scenarios.
+ then be used for such scenarios. Note: for now, the "offload" setting is
+ ignored when set in a defaults section.
Compression is disabled when:
* the request does not advertise a supported compression algorithm in the
@@ -2867,6 +2901,8 @@
http-request { allow | deny | tarpit | auth [realm <realm>] | redirect <rule> |
add-header <name> <fmt> | set-header <name> <fmt> |
del-header <name> | set-nice <nice> | set-log-level <level> |
+ replace-header <name> <match-regex> <replace-fmt> |
+ replace-value <name> <match-regex> <replace-fmt> |
set-tos <tos> | set-mark <mark> |
add-acl(<file name>) <key fmt> |
del-acl(<file name>) <key fmt> |
@@ -2934,6 +2970,47 @@
- "del-header" removes all HTTP header fields whose name is specified in
<name>.
+ - "replace-header" matches the regular expression in all occurrences of
+ header field <name> according to <match-regex>, and replaces them with
+ the <replace-fmt> argument. Format characters are allowed in replace-fmt
+ and work like in <fmt> arguments in "add-header". The match is only
+ case-sensitive. It is important to understand that this action only
+ considers whole header lines, regardless of the number of values they
+ may contain. This usage is suited to headers naturally containing commas
+ in their value, such as If-Modified-Since and so on.
+
+ Example:
+
+ http-request replace-header Cookie foo=([^;]*);(.*) foo=\1;ip=%bi;\2
+
+ applied to:
+
+ Cookie: foo=foobar; expires=Tue, 14-Jun-2016 01:40:45 GMT;
+
+ outputs:
+
+ Cookie: foo=foobar;ip=192.168.1.20; expires=Tue, 14-Jun-2016 01:40:45 GMT;
+
+ assuming the backend IP is 192.168.1.20
+
+ - "replace-value" works like "replace-header" except that it matches the
+ regex against every comma-delimited value of the header field <name>
+ instead of the entire header. This is suited for all headers which are
+ allowed to carry more than one value. An example could be the Accept
+ header.
+
+ Example:
+
+ http-request replace-value X-Forwarded-For ^192\.168\.(.*)$ 172.16.\1
+
+ applied to:
+
+ X-Forwarded-For: 192.168.10.1, 192.168.13.24, 10.0.0.37
+
+ outputs:
+
+ X-Forwarded-For: 172.16.10.1, 172.16.13.24, 10.0.0.37
+
- "set-nice" sets the "nice" factor of the current request being processed.
It only has effect against the other requests being processed at the same
time. The default value is 0, unless altered by the "nice" setting on the
@@ -3058,6 +3135,8 @@
http-response { allow | deny | add-header <name> <fmt> | set-nice <nice> |
set-header <name> <fmt> | del-header <name> |
+ replace-header <name> <regex-match> <replace-fmt> |
+ replace-value <name> <regex-match> <replace-fmt> |
set-log-level <level> | set-mark <mark> | set-tos <tos> |
add-acl(<file name>) <key fmt> |
del-acl(<file name>) <key fmt> |
@@ -3102,6 +3181,47 @@
- "del-header" removes all HTTP header fields whose name is specified in
<name>.
+ - "replace-header" matches the regular expression in all occurrences of
+ header field <name> according to <match-regex>, and replaces them with
+ the <replace-fmt> argument. Format characters are allowed in replace-fmt
+ and work like in <fmt> arguments in "add-header". The match is only
+ case-sensitive. It is important to understand that this action only
+ considers whole header lines, regardless of the number of values they
+ may contain. This usage is suited to headers naturally containing commas
+ in their value, such as Set-Cookie, Expires and so on.
+
+ Example:
+
+ http-response replace-header Set-Cookie (C=[^;]*);(.*) \1;ip=%bi;\2
+
+ applied to:
+
+ Set-Cookie: C=1; expires=Tue, 14-Jun-2016 01:40:45 GMT
+
+ outputs:
+
+ Set-Cookie: C=1;ip=192.168.1.20; expires=Tue, 14-Jun-2016 01:40:45 GMT
+
+ assuming the backend IP is 192.168.1.20.
+
+ - "replace-value" works like "replace-header" except that it matches the
+ regex against every comma-delimited value of the header field <name>
+ instead of the entire header. This is suited for all headers which are
+ allowed to carry more than one value. An example could be the Accept
+ header.
+
+ Example:
+
+ http-response replace-value Cache-control ^public$ private
+
+ applied to:
+
+ Cache-Control: max-age=3600, public
+
+ outputs:
+
+ Cache-Control: max-age=3600, private
+
- "set-nice" sets the "nice" factor of the current request being processed.
It only has effect against the other requests being processed at the same
time. The default value is 0, unless altered by the "nice" setting on the
@@ -3248,7 +3368,7 @@
log global
-log <address> <facility> [<level> [<minlevel>]]
+log <address> [len <length>] <facility> [<level> [<minlevel>]]
no log
Enable per-instance logging of events and traffic.
May be used in sections : defaults | frontend | listen | backend
@@ -3288,6 +3408,18 @@
sign ('$') and optionally enclosing them with braces ('{}'),
similarly to what is done in Bourne shell.
+ <length> is an optional maximum line length. Log lines larger than this
+ value will be truncated before being sent. The reason is that
+ syslog servers act differently on log line length. All servers
+ support the default value of 1024, but some servers simply drop
+ larger lines while others do log them. If a server supports long
+ lines, it may make sense to set this value here in order to avoid
+ truncating long lines. Similarly, if a server drops long lines,
+ it is preferable to truncate them before sending them. Accepted
+ values are 80 to 65535 inclusive. The default value of 1024 is
+ generally fine for all standard usages. Some specific cases of
+ long captures or JSON-formated logs may require larger values.
+
<facility> must be one of the 24 standard syslog facilities :
kern user mail daemon auth syslog lpr news
@@ -4458,13 +4590,14 @@
logging.
-option mysql-check [ user <username> ]
+option mysql-check [ user <username> [ post-41 ] ]
Use MySQL health checks for server testing
May be used in sections : defaults | frontend | listen | backend
yes | no | yes | yes
Arguments :
<username> This is the username which will be used when connecting to MySQL
server.
+ post-41 Send post v4.1 client compatible checks
If you specify a username, the check consists of sending two MySQL packet,
one Client Authentication packet, and one QUIT packet, to correctly close
@@ -6432,7 +6565,7 @@
no | no | yes | yes
Arguments :
- <pattern> is a pattern extraction rule as described in section 7.3. It
+ <pattern> is a sample expression rule as described in section 7.3. It
describes what elements of the incoming request or connection
will be analysed in the hope to find a matching entry in a
stickiness table. This rule is mandatory.
@@ -6498,7 +6631,7 @@
server s2 192.168.1.1:25
See also : "stick-table", "stick on", "nbproc", "bind-process" and section 7
- about ACLs and pattern extraction.
+ about ACLs and samples fetching.
stick on <pattern> [table <table>] [{if | unless} <condition>]
@@ -6551,7 +6684,7 @@
no | no | yes | yes
Arguments :
- <pattern> is a pattern extraction rule as described in section 7.3. It
+ <pattern> is a sample expression rule as described in section 7.3. It
describes what elements of the incoming request or connection
will be analysed, extracted and stored in the table once a
server is selected.
@@ -6631,7 +6764,7 @@
server s2 192.168.1.1:25
See also : "stick-table", "stick on", "nbproc", "bind-process" and section 7
- about ACLs and pattern extraction.
+ about ACLs and sample fetching.
stick-table type {ip | integer | string [len <length>] | binary [len <length>]}
@@ -6667,7 +6800,7 @@
binary a table declared with "type binary" will store binary blocks
of <len> bytes. If the block provided by the pattern
extractor is larger than <len>, it will be truncated before
- being stored. If the block provided by the pattern extractor
+ being stored. If the block provided by the sample expression
is shorter than <len>, it will be padded by 0. When not
specified, the block is automatically limited to 32 bytes.
@@ -6863,7 +6996,7 @@
no | no | yes | yes
Arguments :
- <pattern> is a pattern extraction rule as described in section 7.3. It
+ <pattern> is a sample expression rule as described in section 7.3. It
describes what elements of the response or connection will
be analysed, extracted and stored in the table once a
server is selected.
@@ -7159,7 +7292,7 @@
accept the incoming connection. There is no specific limit to the number of
rules which may be inserted.
- Three types of actions are supported :
+ Five types of actions are supported :
- accept :
accepts the connection if the condition is true (when used with "if")
or false (when used with "unless"). The first such rule executed ends
@@ -7188,6 +7321,18 @@
of load balancers are passed through by traffic coming from public
hosts.
+ - capture <sample> len <length> :
+ This only applies to "tcp-request content" rules. It captures sample
+ expression <sample> from the request buffer, and converts it to a
+ string of at most <len> characters. The resulting string is stored into
+ the next request "capture" slot, so it will possibly appear next to
+ some captured HTTP headers. It will then automatically appear in the
+ logs, and it will be possible to extract it using sample fetch rules to
+ feed it into headers or anything. The length should be limited given
+ that this size will be allocated for each capture during the whole
+ session life. Since it applies to Please check section 7.3 (Fetching
+ samples) and "capture request header" for more information.
+
- { track-sc0 | track-sc1 | track-sc2 } <key> [table <table>] :
enables tracking of sticky counters from current connection. These
rules do not stop evaluation and do not change default action. Two sets
@@ -7202,7 +7347,7 @@
guideline, all may be used everywhere.
These actions take one or two arguments :
- <key> is mandatory, and is a pattern extraction rule as described
+ <key> is mandatory, and is a sample expression rule as described
in section 7.3. It describes what elements of the incoming
request or connection will be analysed, extracted, combined,
and used to select which table entry to update the counters.
@@ -7266,8 +7411,8 @@
Arguments :
<action> defines the action to perform if the condition applies. Valid
actions include : "accept", "reject", "track-sc0", "track-sc1",
- and "track-sc2". See "tcp-request connection" above for their
- signification.
+ "track-sc2" and "capture". See "tcp-request connection" above
+ for their signification.
<condition> is a standard layer 4-7 ACL-based condition (see section 7).
@@ -7295,9 +7440,10 @@
contents. There is no specific limit to the number of rules which may be
inserted.
- Three types of actions are supported :
- - accept :
- - reject :
+ Four types of actions are supported :
+ - accept : the request is accepted
+ - reject : the request is rejected and the connection is closed
+ - capture : the specified sample expression is captured
- { track-sc0 | track-sc1 | track-sc2 } <key> [table <table>]
They have the same meaning as their counter-parts in "tcp-request connection"
@@ -8089,7 +8235,8 @@
accept-proxy
Enforces the use of the PROXY protocol over any connection accepted by any of
- the sockets declared on the same line. The PROXY protocol dictates the layer
+ the sockets declared on the same line. Versions 1 and 2 of the PROXY protocol
+ are supported and correctly detected. The PROXY protocol dictates the layer
3/4 addresses of the incoming connection to be used everywhere an address is
used, with the only exception of "tcp-request connection" rules which will
only see the real connection address. Logs will reflect the addresses
@@ -8152,7 +8299,8 @@
are loaded.
If a directory name is used instead of a PEM file, then all files found in
- that directory will be loaded. This directive may be specified multiple times
+ that directory will be loaded unless their name ends with '.issuer' or
+ '.ocsp' (reserved extensions). This directive may be specified multiple times
in order to load certificates from multiple files or directories. The
certificates will be presented to clients who provide a valid TLS Server Name
Indication field matching one of their CN or alt subjects. Wildcards are
@@ -8175,6 +8323,20 @@
others, e.g. nginx, result in a wrong bundle that will not work for some
clients).
+ For each PEM file, haproxy checks for the presence of file at the same path
+ suffixed by ".ocsp". If such file is found, support for the TLS Certificate
+ Status Request extension (also known as "OCSP stapling") is automatically
+ enabled. The content of this file is optional. If not empty, it must contain
+ a valid OCSP Response in DER format. In order to be valid an OCSP Response
+ must comply with the following rules: it has to indicate a good status,
+ it has to be a single response for the certificate of the PEM file, and it
+ has to be valid at the moment of addition. If these rules are not respected
+ the OCSP Response is ignored and a warning is emitted. In order to identify
+ which certificate an OCSP Response applies to, the issuer's certificate is
+ necessary. If the issuer's certificate is not found in the PEM file, it will
+ be loaded from a file at the same path as the PEM file suffixed by ".issuer"
+ if it exists otherwise it will fail with an error.
+
crt-ignore-err <errors>
This setting is only available when support for OpenSSL was built in. Sets a
comma separated list of errorIDs to ignore during verify at depth == 0. If
@@ -9726,28 +9888,12 @@
transfer binary content in a way that can be reliably transferred (eg:
an SSL ID can be copied in a header).
-lower
- Convert a string sample to lower case. This can only be placed after a string
- sample fetch function or after a transformation keyword returning a string
- type. The result is of type string.
-
-upper
- Convert a string sample to upper case. This can only be placed after a string
- sample fetch function or after a transformation keyword returning a string
- type. The result is of type string.
-
hex
Converts a binary input sample to an hex string containing two hex digits per
input byte. It is used to log or transfer hex dumps of some binary input data
in a way that can be reliably transferred (eg: an SSL ID can be copied in a
header).
-ipmask(<mask>)
- Apply a mask to an IPv4 address, and use the result for lookups and storage.
- This can be used to make all hosts within a certain mask to share the same
- table entries and as such use the same server. The mask can be passed in
- dotted form (eg: 255.255.255.0) or in CIDR form (eg: 24).
-
http_date([<offset>])
Converts an integer supposed to contain a date since epoch to a string
representing this date in a format suitable for use in HTTP header fields. If
@@ -9756,6 +9902,12 @@
emit Date header fields, Expires values in responses when combined with a
positive offset, or Last-Modified values when the offset is negative.
+ipmask(<mask>)
+ Apply a mask to an IPv4 address, and use the result for lookups and storage.
+ This can be used to make all hosts within a certain mask to share the same
+ table entries and as such use the same server. The mask can be passed in
+ dotted form (eg: 255.255.255.0) or in CIDR form (eg: 24).
+
language(<value>[,<default>])
Returns the value with the highest q-factor from a list as extracted from the
"accept-language" header using "req.fhdr". Values with no q-factor have a
@@ -9783,6 +9935,11 @@
use_backend english if en
default_backend choose_your_language
+lower
+ Convert a string sample to lower case. This can only be placed after a string
+ sample fetch function or after a transformation keyword returning a string
+ type. The result is of type string.
+
map(<map_file>[,<default_value>])
map_<match_type>(<map_file>[,<default_value>])
map_<match_type>_<output_type>(<map_file>[,<default_value>])
@@ -9840,6 +9997,11 @@
| `---------------------------- key
`------------------------------------ leading spaces ignored
+upper
+ Convert a string sample to upper case. This can only be placed after a string
+ sample fetch function or after a transformation keyword returning a string
+ type. The result is of type string.
+
7.3.2. Fetching samples from internal states
--------------------------------------------
@@ -10225,19 +10387,17 @@
sc0_kbytes_in([<table>]) : integer
sc1_kbytes_in([<table>]) : integer
sc2_kbytes_in([<table>]) : integer
- Returns the amount of client-to-server data from the currently tracked
- counters, measured in kilobytes over the period configured in the table. The
- test is currently performed on 32-bit integers, which limits values to 4
- terabytes. See also src_kbytes_in.
+ Returns the total amount of client-to-server data from the currently tracked
+ counters, measured in kilobytes. The test is currently performed on 32-bit
+ integers, which limits values to 4 terabytes. See also src_kbytes_in.
sc_kbytes_out(<ctr>[,<table>]) : integer
sc0_kbytes_out([<table>]) : integer
sc1_kbytes_out([<table>]) : integer
sc2_kbytes_out([<table>]) : integer
- Returns the amount of server-to-client data from the currently tracked
- counters, measured in kilobytes over the period configured in the table. The
- test is currently performed on 32-bit integers, which limits values to 4
- terabytes. See also src_kbytes_out.
+ Returns the total amount of server-to-client data from the currently tracked
+ counters, measured in kilobytes. The test is currently performed on 32-bit
+ integers, which limits values to 4 terabytes. See also src_kbytes_out.
sc_sess_cnt(<ctr>[,<table>]) : integer
sc0_sess_cnt([<table>]) : integer
@@ -10401,19 +10561,18 @@
tcp-request connection reject if abuse kill
src_kbytes_in([<table>]) : integer
- Returns the amount of data received from the incoming connection's source
- address in the current proxy's stick-table or in the designated stick-table,
- measured in kilobytes over the period configured in the table. If the address
- is not found, zero is returned. The test is currently performed on 32-bit
- integers, which limits values to 4 terabytes. See also
- sc/sc0/sc1/sc2_kbytes_in.
+ Returns the total amount of data received from the incoming connection's
+ source address in the current proxy's stick-table or in the designated
+ stick-table, measured in kilobytes. If the address is not found, zero is
+ returned. The test is currently performed on 32-bit integers, which limits
+ values to 4 terabytes. See also sc/sc0/sc1/sc2_kbytes_in.
src_kbytes_out([<table>]) : integer
- Returns the amount of data sent to the incoming connection's source address
- in the current proxy's stick-table or in the designated stick-table, measured
- in kilobytes over the period configured in the table. If the address is not
- found, zero is returned. The test is currently performed on 32-bit integers,
- which limits values to 4 terabytes. See also sc/sc0/sc1/sc2_kbytes_out.
+ Returns the total amount of data sent to the incoming connection's source
+ address in the current proxy's stick-table or in the designated stick-table,
+ measured in kilobytes. If the address is not found, zero is returned. The
+ test is currently performed on 32-bit integers, which limits values to 4
+ terabytes. See also sc/sc0/sc1/sc2_kbytes_out.
src_port : integer
Returns an integer value corresponding to the TCP source port of the
@@ -10567,6 +10726,10 @@
Returns the SHA-1 fingerprint of the certificate presented by the client when
the incoming connection was made over an SSL/TLS transport layer. This can be
used to stick a client to a server, or to pass this information to a server.
+ Note that the output is binary, so if you want to pass that signature to the
+ server, you need to encode it in hex or base64, such as in the example below:
+
+ http-request set-header X-SSL-Client-SHA1 %[ssl_c_sha1,hex]
ssl_c_sig_alg : string
Returns the name of the algorithm used to sign the certificate presented by
@@ -12019,7 +12182,7 @@
string formats ("Q").
If a variable is named between square brackets ('[' .. ']') then it is used
-as a pattern extraction rule (see section 7.3). This it useful to add some
+as a sample expression rule (see section 7.3). This it useful to add some
less common information such as the client's SSL certificate's DN, or to log
the key that would be used to store an entry into a stick table.
@@ -12064,7 +12227,7 @@
| H | %CS | captured_response_cookie | string |
| | %H | hostname | string |
| | %ID | unique-id | string |
- | H | %ST | status_code | numeric |
+ | | %ST | status_code | numeric |
| | %T | gmt_date_time | date |
| | %Tc | Tc | numeric |
| | %Tl | local_date_time | date |
@@ -12087,10 +12250,10 @@
| | %fi | frontend_ip (accepting address) | IP |
| | %fp | frontend_port (accepting address) | numeric |
| | %ft | frontend_name_transport ('~' suffix for SSL) | string |
- | H | %hr | captured_request_headers default style | string |
- | H | %hrl | captured_request_headers CLF style | string list |
- | H | %hs | captured_response_headers default style | string |
- | H | %hsl | captured_response_headers CLF style | string list |
+ | | %hr | captured_request_headers default style | string |
+ | | %hrl | captured_request_headers CLF style | string list |
+ | | %hs | captured_response_headers default style | string |
+ | | %hsl | captured_response_headers CLF style | string list |
| | %ms | accept date milliseconds | numeric |
| | %pid | PID | numeric |
| H | %r | http_request | string |
@@ -12755,6 +12918,10 @@
request headers block. These blocks are displayed just before the HTTP request
in the logs.
+As a special case, it is possible to specify an HTTP header capture in a TCP
+frontend. The purpose is to enable logging of headers which will be parsed in
+an HTTP backend if the request is then switched to this HTTP backend.
+
Example :
# This instance chains to the outgoing proxy
listen proxy-out
@@ -12896,46 +13063,86 @@
---------------
The statistics may be consulted either from the unix socket or from the HTTP
-page. Both means provide a CSV format whose fields follow.
-
- 0. pxname: proxy name
- 1. svname: service name (FRONTEND for frontend, BACKEND for backend, any name
- for server)
- 2. qcur: current queued requests
- 3. qmax: max queued requests
- 4. scur: current sessions
- 5. smax: max sessions
- 6. slim: sessions limit
- 7. stot: total sessions
- 8. bin: bytes in
- 9. bout: bytes out
- 10. dreq: denied requests
- 11. dresp: denied responses
- 12. ereq: request errors
- 13. econ: connection errors
- 14. eresp: response errors (among which srv_abrt)
- 15. wretr: retries (warning)
- 16. wredis: redispatches (warning)
- 17. status: status (UP/DOWN/NOLB/MAINT/MAINT(via)...)
- 18. weight: server weight (server), total weight (backend)
- 19. act: server is active (server), number of active servers (backend)
- 20. bck: server is backup (server), number of backup servers (backend)
- 21. chkfail: number of failed checks
- 22. chkdown: number of UP->DOWN transitions
- 23. lastchg: last status change (in seconds)
- 24. downtime: total downtime (in seconds)
- 25. qlimit: queue limit
- 26. pid: process id (0 for first instance, 1 for second, ...)
- 27. iid: unique proxy id
- 28. sid: service id (unique inside a proxy)
- 29. throttle: warm up status
- 30. lbtot: total number of times a server was selected
- 31. tracked: id of proxy/server if tracking is enabled
- 32. type (0=frontend, 1=backend, 2=server, 3=socket)
- 33. rate: number of sessions per second over last elapsed second
- 34. rate_lim: limit on new sessions per second
- 35. rate_max: max number of new sessions per second
- 36. check_status: status of last health check, one of:
+page. Both means provide a CSV format whose fields follow. The first line
+begins with a sharp ('#') and has one word per comma-delimited field which
+represents the title of the column. All other lines starting at the second one
+use a classical CSV format using a comma as the delimiter, and the double quote
+('"') as an optional text delimiter, but only if the enclosed text is ambiguous
+(if it contains a quote or a comma). The double-quote character ('"') in the
+text is doubled ('""'), which is the format that most tools recognize. Please
+do not insert any column before these ones in order not to break tools which
+use hard-coded column positions.
+
+In brackets after each field name are the types which may have a value for
+that field. The types are L (Listeners), F (Frontends), B (Backends), and
+S (Servers).
+
+ 0. pxname [LFBS]: proxy name
+ 1. svname [LFBS]: service name (FRONTEND for frontend, BACKEND for backend,
+ any name for server/listener)
+ 2. qcur [..BS]: current queued requests. For the backend this reports the
+ number queued without a server assigned.
+ 3. qmax [..BS]: max value of qcur
+ 4. scur [LFBS]: current sessions
+ 5. smax [LFBS]: max sessions
+ 6. slim [LFBS]: configured session limit
+ 7. stot [LFBS]: cumulative number of connections
+ 8. bin [LFBS]: bytes in
+ 9. bout [LFBS]: bytes out
+ 10. dreq [LFB.]: requests denied because of security concerns.
+ - For tcp this is because of a matched tcp-request content rule.
+ - For http this is because of a matched http-request or tarpit rule.
+ 11. dresp [LFBS]: responses denied because of security concerns.
+ - For http this is because of a matched http-request rule, or
+ "option checkcache".
+ 12. ereq [LF..]: request errors. Some of the possible causes are:
+ - early termination from the client, before the request has been sent.
+ - read error from the client
+ - client timeout
+ - client closed connection
+ - various bad requests from the client.
+ - request was tarpitted.
+ 13. econ [..BS]: number of requests that encountered an error trying to
+ connect to a backend server. The backend stat is the sum of the stat
+ for all servers of that backend, plus any connection errors not
+ associated with a particular server (such as the backend having no
+ active servers).
+ 14. eresp [..BS]: response errors. srv_abrt will be counted here also.
+ Some other errors are:
+ - write error on the client socket (won't be counted for the server stat)
+ - failure applying filters to the response.
+ 15. wretr [..BS]: number of times a connection to a server was retried.
+ 16. wredis [..BS]: number of times a request was redispatched to another
+ server. The server value counts the number of times that server was
+ switched away from.
+ 17. status [LFBS]: status (UP/DOWN/NOLB/MAINT/MAINT(via)...)
+ 18. weight [..BS]: server weight (server), total weight (backend)
+ 19. act [..BS]: server is active (server), number of active servers (backend)
+ 20. bck [..BS]: server is backup (server), number of backup servers (backend)
+ 21. chkfail [...S]: number of failed checks. (Only counts checks failed when
+ the server is up.)
+ 22. chkdown [..BS]: number of UP->DOWN transitions. The backend counter counts
+ transitions to the whole backend being down, rather than the sum of the
+ counters for each server.
+ 23. lastchg [..BS]: number of seconds since the last UP<->DOWN transition
+ 24. downtime [..BS]: total downtime (in seconds). The value for the backend
+ is the downtime for the whole backend, not the sum of the server downtime.
+ 25. qlimit [...S]: configured maxqueue for the server, or nothing in the
+ value is 0 (default, meaning no limit)
+ 26. pid [LFBS]: process id (0 for first instance, 1 for second, ...)
+ 27. iid [LFBS]: unique proxy id
+ 28. sid [L..S]: server id (unique inside a proxy)
+ 29. throttle [...S]: current throttle percentage for the server, when
+ slowstart is active, or no value if not in slowstart.
+ 30. lbtot [..BS]: total number of times a server was selected, either for new
+ sessions, or when re-dispatching. The server counter is the number
+ of times that server was selected.
+ 31. tracked [...S]: id of proxy/server if tracking is enabled.
+ 32. type [LFBS]: (0=frontend, 1=backend, 2=server, 3=socket/listener)
+ 33. rate [.FBS]: number of sessions per second over last elapsed second
+ 34. rate_lim [.F..]: configured limit on new sessions per second
+ 35. rate_max [.FBS]: max number of new sessions per second
+ 36. check_status [...S]: status of last health check, one of:
UNK -> unknown
INI -> initializing
SOCKERR -> socket error
@@ -12952,25 +13159,36 @@
L7TOUT -> layer 7 (HTTP/SMTP) timeout
L7RSP -> layer 7 invalid response - protocol error
L7STS -> layer 7 response error, for example HTTP 5xx
- 37. check_code: layer5-7 code, if available
- 38. check_duration: time in ms took to finish last health check
- 39. hrsp_1xx: http responses with 1xx code
- 40. hrsp_2xx: http responses with 2xx code
- 41. hrsp_3xx: http responses with 3xx code
- 42. hrsp_4xx: http responses with 4xx code
- 43. hrsp_5xx: http responses with 5xx code
- 44. hrsp_other: http responses with other codes (protocol error)
- 45. hanafail: failed health checks details
- 46. req_rate: HTTP requests per second over last elapsed second
- 47. req_rate_max: max number of HTTP requests per second observed
- 48. req_tot: total number of HTTP requests received
- 49. cli_abrt: number of data transfers aborted by the client
- 50. srv_abrt: number of data transfers aborted by the server (inc. in eresp)
- 51. comp_in: number of HTTP response bytes fed to the compressor
- 52. comp_out: number of HTTP response bytes emitted by the compressor
- 53. comp_byp: number of bytes that bypassed the HTTP compressor (CPU/BW limit)
- 54. comp_rsp: number of HTTP responses that were compressed
- 55. lastsess: number of seconds since last session assigned to server/backend
+ 37. check_code [...S]: layer5-7 code, if available
+ 38. check_duration [...S]: time in ms took to finish last health check
+ 39. hrsp_1xx [.FBS]: http responses with 1xx code
+ 40. hrsp_2xx [.FBS]: http responses with 2xx code
+ 41. hrsp_3xx [.FBS]: http responses with 3xx code
+ 42. hrsp_4xx [.FBS]: http responses with 4xx code
+ 43. hrsp_5xx [.FBS]: http responses with 5xx code
+ 44. hrsp_other [.FBS]: http responses with other codes (protocol error)
+ 45. hanafail [...S]: failed health checks details
+ 46. req_rate [.F..]: HTTP requests per second over last elapsed second
+ 47. req_rate_max [.F..]: max number of HTTP requests per second observed
+ 48. req_tot [.F..]: total number of HTTP requests received
+ 49. cli_abrt [..BS]: number of data transfers aborted by the client
+ 50. srv_abrt [..BS]: number of data transfers aborted by the server
+ (inc. in eresp)
+ 51. comp_in [.FB.]: number of HTTP response bytes fed to the compressor
+ 52. comp_out [.FB.]: number of HTTP response bytes emitted by the compressor
+ 53. comp_byp [.FB.]: number of bytes that bypassed the HTTP compressor
+ (CPU/BW limit)
+ 54. comp_rsp [.FB.]: number of HTTP responses that were compressed
+ 55. lastsess [..BS]: number of seconds since last session assigned to
+ server/backend
+ 56. last_chk [...S]: last health check contents or textual error
+ 57. last_agt [...S]: last agent check contents or textual error
+ 58. qtime [..BS]: the average queue time in ms over the 1024 last requests
+ 59. ctime [..BS]: the average connect time in ms over the 1024 last requests
+ 60. rtime [..BS]: the average response time in ms over the 1024 last requests
+ (0 for TCP)
+ 61. ttime [..BS]: the average total session time in ms over the 1024 last
+ requests
9.2. Unix Socket commands
@@ -13384,6 +13602,18 @@
Change a server's weight to the value passed in argument. This is the exact
equivalent of the "set weight" command below.
+set ssl ocsp-response <response>
+ This command is used to update an OCSP Response for a certificate (see "crt"
+ on "bind" lines). Same controls are performed as during the initial loading of
+ the response. The <response> must be passed as a base64 encoded string of the
+ DER encoded response from the OCSP server.
+
+ Example:
+ openssl ocsp -issuer issuer.pem -cert server.pem \
+ -host ocsp.issuer.com:80 -respout resp.der
+ echo "set ssl ocsp-response $(base64 -w 10000 resp.der)" | \
+ socat stdio /var/run/haproxy.stat
+
set table <table> key <key> [data.<data_type> <value>]*
Create or update a stick-table entry in the table. If the key is not present,
an entry is inserted. See stick-table in section 4.2 to find all possible
@@ -13639,7 +13869,7 @@
endless transfer is ongoing. Such terminated sessions are reported with a 'K'
flag in the logs.
-shutdown sessions <backend>/<server>
+shutdown sessions server <backend>/<server>
Immediately terminate all the sessions attached to the specified server. This
can be used to terminate long-running sessions after a server is put into
maintenance mode, for instance. Such terminated sessions are reported with a
|
[-]
[+]
|
Added |
haproxy-1.5.3.tar.gz/doc/design-thoughts/binding-possibilities.txt
^
|
@@ -0,0 +1,167 @@
+2013/10/10 - possibilities for setting source and destination addresses
+
+
+When establishing a connection to a remote device, this device is designated
+as a target, which designates an entity defined in the configuration. A same
+target appears only once in a configuration, and multiple targets may share
+the same settings if needed.
+
+The following types of targets are currently supported :
+
+ - listener : all connections with this type of target come from clients ;
+ - server : connections to such targets are for "server" lines ;
+ - peer : connections to such target address "peer" lines in "peers"
+ sections ;
+ - proxy : these targets are used by "dispatch", "option transparent"
+ or "option http_proxy" statements.
+
+A connection might not be reused between two different targets, even if all
+parameters seem similar. One of the reason is that some parameters are specific
+to the target and are not easy or not cheap to compare (eg: bind to interface,
+mss, ...).
+
+A number of source and destination addresses may be set for a given target.
+
+ - listener :
+ - the "from" address:port is set by accept()
+
+ - the "to" address:port is set if conn_get_to_addr() is called
+
+ - peer :
+ - the "from" address:port is not set
+
+ - the "to" address:port is static and dependent only on the peer
+
+ - server :
+ - the "from" address may be set alone when "source" is used with
+ a forced IP address, or when "usesrc clientip" is used.
+
+ - the "from" port may be set only combined with the address when
+ "source" is used with IP:port, IP:port-range or "usesrc client" is
+ used. Note that in this case, both the address and the port may be
+ 0, meaning that the kernel will pick the address or port and that
+ the final value might not match the one explicitly set (eg:
+ important for logging).
+
+ - the "from" address may be forced from a header which implies it
+ may change between two consecutive requests on the same connection.
+
+ - the "to" address and port are set together when connecting to a
+ regular server, or by copying the client's IP address when
+ "server 0.0.0.0" is used. Note that the destination port may be
+ an offset applied to the original destination port.
+
+ - proxy :
+ - the "from" address may be set alone when "source" is used with a
+ forced IP address or when "usesrc clientip" is used.
+
+ - the "from" port may be set only combined with the address when
+ "source" is used with IP:port or with "usesrc client". There is
+ no ip:port range for a proxy as of now. Same comment applies as
+ above when port and/or address are 0.
+
+ - the "from" address may be forced from a header which implies it
+ may change between two consecutive requests on the same connection.
+
+ - the "to" address and port are set together, either by configuration
+ when "dispatch" is used, or dynamically when "transparent" is used
+ (1:1 with client connection) or "option http_proxy" is used, where
+ each client request may lead to a different destination address.
+
+
+At the moment, there are some limits in what might happen between multiple
+concurrent requests to a same target.
+
+ - peers parameter do not change, so no problem.
+
+ - server parameters may change in this way :
+ - a connection may require a source bound to an IP address found in a
+ header, which will fall back to the "source" settings if the address
+ is not found in this header. This means that the source address may
+ switch between a dynamically forced IP address and another forced
+ IP and/or port range.
+
+ - if the element is not found (eg: header), the remaining "forced"
+ source address might very well be empty (unset), so the connection
+ reuse is acceptable when switching in that direction.
+
+ - it is not possible to switch between client and clientip or any of
+ these and hdr_ip() because they're exclusive.
+
+ - using a source address/port belonging to a port range is compatible
+ with connection reuse because there is a single range per target, so
+ switching from a range to another range means we remain in the same
+ range.
+
+ - destination address may currently not change since the only possible
+ case for dynamic destination address setting is the transparent mode,
+ reproducing the client's destination address.
+
+ - proxy parameters may change in this way :
+ - a connection may require a source bound to an IP address found in a
+ header, which will fall back to the "source" settings if the address
+ is not found in this header. This means that the source address may
+ switch between a dynamically forced IP address and another forced
+ IP and/or port range.
+
+ - if the element is not found (eg: header), the remaining "forced"
+ source address might very well be empty (unset), so the connection
+ reuse is acceptable when switching in that direction.
+
+ - it is not possible to switch between client and clientip or any of
+ these and hdr_ip() because they're exclusive.
+
+ - proxies do not support port ranges at the moment.
+
+ - destination address might change in the case where "option http_proxy"
+ is used.
+
+So, for each source element (IP, port), we want to know :
+ - if the element was assigned by static configuration (eg: ":80")
+ - if the element was assigned from a connection-specific value (eg: usesrc clientip)
+ - if the element was assigned from a configuration-specific range (eg: 1024-65535)
+ - if the element was assigned from a request-specific value (eg: hdr_ip(xff))
+ - if the element was not assigned at all
+
+For the destination, we want to know :
+ - if the element was assigned by static configuration (eg: ":80")
+ - if the element was assigned from a connection-specific value (eg: transparent)
+ - if the element was assigned from a request-specific value (eg: http_proxy)
+
+We don't need to store the information about the origin of the dynamic value
+since we have the value itself. So in practice we have :
+ - default value, unknown (not yet checked with getsockname/getpeername)
+ - default value, known (check done)
+ - forced value (known)
+ - forced range (known)
+
+We can't do that on an ip:port basis because the port may be fixed regardless
+of the address and conversely.
+
+So that means :
+
+ enum {
+ CO_ADDR_NONE = 0, /* not set, unknown value */
+ CO_ADDR_KNOWN = 1, /* not set, known value */
+ CO_ADDR_FIXED = 2, /* fixed value, known */
+ CO_ADDR_RANGE = 3, /* from assigned range, known */
+ } conn_addr_values;
+
+ unsigned int new_l3_src_status:2;
+ unsigned int new_l4_src_status:2;
+ unsigned int new_l3_dst_status:2;
+ unsigned int new_l4_dst_status:2;
+
+ unsigned int cur_l3_src_status:2;
+ unsigned int cur_l4_src_status:2;
+ unsigned int cur_l3_dsp_status:2;
+ unsigned int cur_l4_dst_status:2;
+
+ unsigned int new_family:2;
+ unsigned int cur_family:2;
+
+Note: this obsoletes CO_FL_ADDR_FROM_SET and CO_FL_ADDR_TO_SET. These flags
+must be changed to individual l3+l4 checks ORed between old and new values,
+or better, set to cur only which will inherit new.
+
+In the connection, these values may be merged in the same word as err_code.
|
[-]
[+]
|
Added |
haproxy-1.5.3.tar.gz/doc/design-thoughts/connection-reuse.txt
^
|
@@ -0,0 +1,139 @@
+2013/10/17 - server connection management and reuse
+
+Current state
+-------------
+
+At the moment, a connection entity is needed to carry any address
+information. This means in the following situations, we need a server
+connection :
+
+- server is elected and the server's destination address is set
+
+- transparent mode is elected and the destination address is set from
+ the incoming connection
+
+- proxy mode is enabled, and the destination's address is set during
+ the parsing of the HTTP request
+
+- connection to the server fails and must be retried on the same
+ server using the same parameters, especially the destination
+ address (SN_ADDR_SET not removed)
+
+
+On the accepting side, we have further requirements :
+
+- allocate a clean connection without a stream interface
+
+- incrementally set the accepted connection's parameters without
+ clearing it, and keep track of what is set (eg: getsockname).
+
+- initialize a stream interface in established mode
+
+- attach the accepted connection to a stream interface
+
+
+This means several things :
+
+- the connection has to be allocated on the fly the first time it is
+ needed to store the source or destination address ;
+
+- the connection has to be attached to the stream interface at this
+ moment ;
+
+- it must be possible to incrementally set some settings on the
+ connection's addresses regardless of the connection's current state
+
+- the connection must not be released across connection retries ;
+
+- it must be possible to clear a connection's parameters for a
+ redispatch without having to detach/attach the connection ;
+
+- we need to allocate a connection without an existing stream interface
+
+So on the accept() side, it looks like this :
+
+ fd = accept();
+ conn = new_conn();
+ get_some_addr_info(&conn->addr);
+ ...
+ si = new_si();
+ si_attach_conn(si, conn);
+ si_set_state(si, SI_ST_EST);
+ ...
+ get_more_addr_info(&conn->addr);
+
+On the connect() side, it looks like this :
+
+ si = new_si();
+ while (!properly_connected) {
+ if (!(conn = si->end)) {
+ conn = new_conn();
+ conn_clear(conn);
+ si_attach_conn(si, conn);
+ }
+ else {
+ if (connected) {
+ f = conn->flags & CO_FL_XPRT_TRACKED;
+ conn->flags &= ~CO_FL_XPRT_TRACKED;
+ conn_close(conn);
+ conn->flags |= f;
+ }
+ if (!correct_dest)
+ conn_clear(conn);
+ }
+ set_some_addr_info(&conn->addr);
+ si_set_state(si, SI_ST_CON);
+ ...
+ set_more_addr_info(&conn->addr);
+ conn->connect();
+ if (must_retry) {
+ close_conn(conn);
+ }
+ }
+
+Note: we need to be able to set the control and transport protocols.
+On outgoing connections, this is set once we know the destination address.
+On incoming connections, this is set the earliest possible (once we know
+the source address).
+
+The problem analysed below was solved on 2013/10/22
+
+| ==> the real requirement is to know whether a connection is still valid or not
+| before deciding to close it. CO_FL_CONNECTED could be enough, though it
+| will not indicate connections that are still waiting for a connect to occur.
+| This combined with CO_FL_WAIT_L4_CONN and CO_FL_WAIT_L6_CONN should be OK.
+|
+| Alternatively, conn->xprt could be used for this, but needs some careful checks
+| (it's used by conn_full_close at least).
+|
+| Right now, conn_xprt_close() checks conn->xprt and sets it to NULL.
+| conn_full_close() also checks conn->xprt and sets it to NULL, except
+| that the check on ctrl is performed within xprt. So conn_xprt_close()
+| followed by conn_full_close() will not close the file descriptor.
+| Note that conn_xprt_close() is never called, maybe we should kill it ?
+|
+| Note: at the moment, it's problematic to leave conn->xprt to NULL before doing
+| xprt_init() because we might end up with a pending file descriptor. Or at
+| least with some transport not de-initialized. We might thus need
+| conn_xprt_close() when conn_xprt_init() fails.
+|
+| The fd should be conditionned by ->ctrl only, and the transport layer by ->xprt.
+|
+| - conn_prepare_ctrl(conn, ctrl)
+| - conn_prepare_xprt(conn, xprt)
+| - conn_prepare_data(conn, data)
+|
+| Note: conn_xprt_init() needs conn->xprt so it's not a problem to set it early.
+|
+| One problem might be with conn_xprt_close() not being able to know if xprt_init()
+| was called or not. That's where it might make sense to only set ->xprt during init.
+| Except that it does not fly with outgoing connections (xprt_init is called after
+| connect()).
+|
+| => currently conn_xprt_close() is only used by ssl_sock.c and decides whether
+| to do something based on ->xprt_ctx which is set by ->init() from xprt_init().
+| So there is nothing to worry about. We just need to restore conn_xprt_close()
+| and rely on ->ctrl to close the fd instead of ->xprt.
+|
+| => we have the same issue with conn_ctrl_close() : when is the fd supposed to be
+| valid ? On outgoing connections, the control is set much before the fd...
|
[-]
[+]
|
Added |
haproxy-1.5.3.tar.gz/doc/design-thoughts/entities-v2.txt
^
|
@@ -0,0 +1,276 @@
+2012/07/05 - Connection layering and sequencing
+
+
+An FD has a state :
+ - CLOSED
+ - READY
+ - ERROR (?)
+ - LISTEN (?)
+
+A connection has a state :
+ - CLOSED
+ - ACCEPTED
+ - CONNECTING
+ - ESTABLISHED
+ - ERROR
+
+A stream interface has a state :
+ - INI, REQ, QUE, TAR, ASS, CON, CER, EST, DIS, CLO
+
+Note that CON and CER might be replaced by EST if the connection state is used
+instead. CON might even be more suited than EST to indicate that a connection
+is known.
+
+
+si_shutw() must do :
+
+ data_shutw()
+ if (shutr) {
+ data_close()
+ ctrl_shutw()
+ ctrl_close()
+ }
+
+si_shutr() must do :
+ data_shutr()
+ if (shutw) {
+ data_close()
+ ctrl_shutr()
+ ctrl_close()
+ }
+
+Each of these steps may fail, in which case the step must be retained and the
+operations postponed in an asynchronous task.
+
+The first asynchronous data_shut() might already fail so it is mandatory to
+save the other side's status with the connection in order to let the async task
+know whether the 3 next steps must be performed.
+
+The connection (or perhaps the FD) needs to know :
+ - the desired close operations : DSHR, DSHW, CSHR, CSHW
+ - the completed close operations : DSHR, DSHW, CSHR, CSHW
+
+
+On the accept() side, we probably need to know :
+ - if a header is expected (eg: accept-proxy)
+ - if this header is still being waited for
+ => maybe both info might be combined into one bit
+
+ - if a data-layer accept() is expected
+ - if a data-layer accept() has been started
+ - if a data-layer accept() has been performed
+ => possibly 2 bits, to indicate the need to free()
+
+On the connect() side, we need to konw :
+ - the desire to send a header (eg: send-proxy)
+ - if this header has been sent
+ => maybe both info might be combined
+
+ - if a data-layer connect() is expected
+ - if a data-layer connect() has been started
+ - if a data-layer connect() has been completed
+ => possibly 2 bits, to indicate the need to free()
+
+On the response side, we also need to know :
+ - the desire to send a header (eg: health check response for monitor-net)
+ - if this header was sent
+ => might be the same as sending a header over a new connection
+
+Note: monitor-net has precedence over proxy proto and data layers. Same for
+ health mode.
+
+For multi-step operations, use 2 bits :
+ 00 = operation not desired, not performed
+ 10 = operation desired, not started
+ 11 = operation desired, started but not completed
+ 01 = operation desired, started and completed
+
+ => X != 00 ==> operation desired
+ X & 01 ==> operation at least started
+ X & 10 ==> operation not completed
+
+Note: no way to store status information for error reporting.
+
+Note2: it would be nice if "tcp-request connection" rules could work at the
+connection level, just after headers ! This means support for tracking stick
+tables, possibly not too much complicated.
+
+
+Proposal for incoming connection sequence :
+
+- accept()
+- if monitor-net matches or if mode health => try to send response
+- if accept-proxy, wait for proxy request
+- if tcp-request connection, process tcp rules and possibly keep the
+ pointer to stick-table
+- if SSL is enabled, switch to SSL handshake
+- then switch to DATA state and instantiate a session
+
+We just need a map of handshake handlers on the connection. They all manage the
+FD status themselves and set the callbacks themselves. If their work succeeds,
+they remove themselves from the list. If it fails, they remain subscribed and
+enable the required polling until they are woken up again or the timeout strikes.
+
+Identified handshake handlers for incoming connections :
+ - HH_HEALTH (tries to send OK and dies)
+ - HH_MONITOR_IN (matches src IP and adds/removes HH_SEND_OK/HH_SEND_HTTP_OK)
+ - HH_SEND_OK (tries to send "OK" and dies)
+ - HH_SEND_HTTP_OK (tries to send "HTTP/1.0 200 OK" and dies)
+ - HH_ACCEPT_PROXY (waits for PROXY line and parses it)
+ - HH_TCP_RULES (processes TCP rules)
+ - HH_SSL_HS (starts SSL handshake)
+ - HH_ACCEPT_SESSION (instanciates a session)
+
+Identified handshake handlers for outgoing connections :
+ - HH_SEND_PROXY (tries to build and send the PROXY line)
+ - HH_SSL_HS (starts SSL handshake)
+
+For the pollers, we could check that handshake handlers are not 0 and decide to
+call a generic connection handshake handler instead of usual callbacks. Problem
+is that pollers don't know connections, they know fds. So entities which manage
+handlers should update change the FD callbacks accordingly.
+
+With a bit of care, we could have :
+ - HH_SEND_LAST_CHUNK (sends the chunk pointed to by a pointer and dies)
+ => merges HEALTH, SEND_OK and SEND_HTTP_OK
+
+It sounds like the ctrl vs data state for the connection are per-direction
+(eg: support an async ctrl shutw while still reading data).
+
+Also support shutr/shutw status at L4/L7.
+
+In practice, what we really need is :
+
+shutdown(conn) =
+ conn.data.shut()
+ conn.ctrl.shut()
+ conn.fd.shut()
+
+close(conn) =
+ conn.data.close()
+ conn.ctrl.close()
+ conn.fd.close()
+
+With SSL over Remote TCP (RTCP + RSSL) to reach the server, we would have :
+
+ HTTP -> RTCP+RSSL connection <-> RTCP+RRAW connection -> TCP+SSL connection
+
+The connection has to be closed at 3 places after a successful response :
+ - DATA (RSSL over RTCP)
+ - CTRL (RTCP to close connection to server)
+ - SOCK (FD to close connection to second process)
+
+Externally, the connection is seen with very few flags :
+ - SHR
+ - SHW
+ - ERR
+
+We don't need a CLOSED flag as a connection must always be detached when it's closed.
+
+The internal status doesn't need to be exposed :
+ - FD allocated (Y/N)
+ - CTRL initialized (Y/N)
+ - CTRL connected (Y/N)
+ - CTRL handlers done (Y/N)
+ - CTRL failed (Y/N)
+ - CTRL shutr (Y/N)
+ - CTRL shutw (Y/N)
+ - DATA initialized (Y/N)
+ - DATA connected (Y/N)
+ - DATA handlers done (Y/N)
+ - DATA failed (Y/N)
+ - DATA shutr (Y/N)
+ - DATA shutw (Y/N)
+
+(note that having flags for operations needing to be completed might be easier)
+--------------
+
+Maybe we need to be able to call conn->fdset() and conn->fdclr() but it sounds
+very unlikely since the only functions manipulating this are in the code of
+the data/ctrl handlers.
+
+FDSET/FDCLR cannot be directly controlled by the stream interface since it also
+depends on the DATA layer (WANT_READ/WANT_WRITE).
+
+But FDSET/FDCLR is probably controlled by who owns the connection (eg: DATA).
+
+Example: an SSL conn relies on an FD. The buffer is full, and wants the conn to
+stop reading. It must not stop the FD itself. It is the read function which
+should notice that it has nothing to do with a read wake-up, which needs to
+disable reading.
+
+Conversely, when calling conn->chk_rcv(), the reader might get a WANT_READ or
+even WANT_WRITE and adjust the FDs accordingly.
+
+------------------------
+
+OK, the problem is simple : we don't manipulate the FD at the right level.
+We should have :
+ ->connect(), ->chk_snd(), ->chk_rcv(), ->shutw(), ->shutr() which are
+ called from the upper layer (buffer)
+ ->recv(), ->send(), called from the lower layer
+
+Note that the SHR is *reported* by lower layer but can be forced by upper
+layer. In this case it's like a delayed abort. The difficulty consists in
+knowing the output data were correctly read. Probably we'd need to drain
+incoming data past the active shutr().
+
+The only four purposes of the top-down shutr() call are :
+ - acknowledge a shut read report : could probably be done better
+ - read timeout => disable reading : it's a delayed abort. We want to
+ report that the buffer is SHR, maybe even the connection, but the
+ FD clearly isn't.
+ - read abort due to error on the other side or desire to close (eg:
+ http-server-close) : delayed abort
+ - complete abort
+
+The active shutr() is problematic as we can't disable reading if we expect some
+exchanges for data acknowledgement. We probably need to drain data only until
+the shutw() has been performed and ACKed.
+
+A connection shut down for read would behave like this :
+
+ 1) bidir exchanges
+
+ 2) shutr() => read_abort_pending=1
+
+ 3) drain input, still send output
+
+ 4) shutw()
+
+ 5) drain input, wait for read0 or ack(shutw)
+
+ 6) close()
+
+--------------------- 2012/07/05 -------------------
+
+Communications must be performed this way :
+
+ connection <-> channel <-> connection
+
+A channel is composed of flags and stats, and may store data in either a buffer
+or a pipe. We need low-layer operations between sockets and buffers or pipes.
+Right now we only support sockets, but later we might support remote sockets
+and maybe pipes or shared memory segments.
+
+So we need :
+
+ - raw_sock_to_buf() => receive raw data from socket into buffer
+ - raw_sock_to_pipe => receive raw data from socket into pipe (splice in)
+ - raw_sock_from_buf() => send raw data from buffer to socket
+ - raw_sock_from_pipe => send raw data from pipe to socket (splice out)
+
+ - ssl_sock_to_buf() => receive ssl data from socket into buffer
+ - ssl_sock_to_pipe => receive ssl data from socket into a pipe (NULL)
+ - ssl_sock_from_buf() => send ssl data from buffer to socket
+ - ssl_sock_from_pipe => send ssl data from pipe to socket (NULL)
+
+These functions should set such status flags :
+
+#define ERR_IN 0x01
+#define ERR_OUT 0x02
+#define SHUT_IN 0x04
+#define SHUT_OUT 0x08
+#define EMPTY_IN 0x10
+#define FULL_OUT 0x20
+
|
[-]
[+]
|
Changed |
haproxy-1.5.3.tar.gz/doc/internals/body-parsing.txt
^
|
@@ -67,12 +67,17 @@
automatically adjusted to the number of bytes already inspected.
msg.sov : start of value. First character of the header's value in the header
- states, start of the body in the data states until headers are
- forwarded. This offset is automatically adjusted when inserting or
- removing some headers. In data states, it always constains the size
- of the whole HTTP headers (including the trailing CRLF) that needs
- to be forwarded before the first byte of body. Once the headers are
- forwarded, this value drops to zero.
+ states, start of the body in the data states. Strictly positive
+ values indicate that headers were not forwarded yet (<buf.p> is
+ before the start of the body), and null or positive values are seen
+ after headers are forwarded (<buf.p> is at or past the start of the
+ body). The value stops changing when data start to leave the buffer
+ (in order to avoid integer overflows). So the maximum possible range
+ is -<buf.size> to +<buf.size>. This offset is automatically adjusted
+ when inserting or removing some headers. It is useful to rewind the
+ request buffer to the beginning of the body at any phase. The
+ response buffer does not really use it since it is immediately
+ forwarded to the client.
msg.sol : start of line. Points to the beginning of the current header line
while parsing headers. It is cleared to zero in the BODY state,
@@ -97,7 +102,8 @@
states nor by forwarding.
The beginning of the message headers can always be found this way even after
-headers have been forwarded :
+headers or data have been forwarded, provided that everything is still present
+in the buffer :
headers = buf.p + msg->sov - msg->eoh - msg->eol
|
[-]
[+]
|
Added |
haproxy-1.5.3.tar.gz/doc/internals/sequence.fig
^
|
@@ -0,0 +1,123 @@
+#FIG 3.2 Produced by xfig version 3.2.5-alpha5
+Portrait
+Center
+Metric
+A4
+100.00
+Single
+-2
+1200 2
+6 900 945 3015 1800
+6 1035 1215 3015 1800
+6 1035 1215 3015 1350
+2 2 0 1 26 6 51 -1 20 0.000 0 0 -1 0 0 5
+ 1035 1215 1620 1215 1620 1350 1035 1350 1035 1215
+4 0 0 50 -1 12 7 0.0000 4 90 1275 1710 1305 Standard settings\001
+-6
+6 1035 1440 2385 1575
+2 2 0 1 9 11 51 -1 20 0.000 0 0 -1 0 0 5
+ 1035 1440 1620 1440 1620 1575 1035 1575 1035 1440
+4 0 0 50 -1 12 7 0.0000 4 60 675 1710 1530 Rule sets\001
+-6
+6 1035 1665 2790 1800
+2 2 0 1 13 2 52 -1 20 0.000 0 0 -1 0 0 5
+ 1035 1665 1620 1665 1620 1800 1035 1800 1035 1665
+4 0 0 50 -1 12 7 0.0000 4 75 1050 1710 1755 HTTP mode only\001
+-6
+-6
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
+ 945 1125 945 1800
+4 0 0 50 -1 17 10 0.0000 4 150 615 900 1080 Captions\001
+-6
+6 450 2250 3510 3195
+4 0 0 50 -1 16 10 0.0000 4 150 2865 450 2385 Each time a poller detects an activity on a\001
+4 0 0 50 -1 16 10 0.0000 4 150 2940 450 2580 listening socket, this sequence is executed.\001
+4 0 0 50 -1 16 10 0.0000 4 150 3000 450 2775 Note that stream_sock_accept() loops until\001
+4 0 0 50 -1 16 10 0.0000 4 150 3030 450 2970 accept() returns an error or tune.maxaccept\001
+4 0 0 50 -1 16 10 0.0000 4 150 1830 450 3165 loops have been executed.\001
+-6
+6 450 3375 3420 4275
+4 0 0 50 -1 16 10 0.0000 4 150 2535 450 3510 Once the session is started, function\001
+4 0 0 50 -1 16 10 0.0000 4 150 2880 450 3705 process_session() will be called once then\001
+4 0 0 50 -1 16 10 0.0000 4 150 2895 450 3900 each time an activity is detected on any of\001
+4 0 0 50 -1 16 10 0.0000 4 150 2955 450 4095 monitored file descriptors belonging to the\001
+4 0 0 50 -1 16 10 0.0000 4 120 555 450 4275 session.\001
+-6
+6 4230 945 6480 1125
+2 2 0 1 26 6 51 -1 20 0.000 0 0 -1 0 0 5
+ 4230 945 6345 945 6345 1125 4230 1125 4230 945
+4 0 0 50 -1 14 10 0.0000 4 105 2205 4275 1080 rate-limit sessions ?\001
+-6
+6 4455 1620 7065 1800
+2 2 0 1 26 6 51 -1 20 0.000 0 0 -1 0 0 5
+ 4455 1620 6885 1620 6885 1800 4455 1800 4455 1620
+4 0 0 50 -1 14 10 0.0000 4 135 2520 4521 1755 monitor-net (mode=tcp) ?\001
+-6
+6 4455 1845 7470 2025
+2 2 0 1 9 11 51 -1 20 0.000 0 0 -1 0 0 5
+ 4455 1845 7290 1845 7290 2025 4455 2025 4455 1845
+4 0 0 50 -1 14 10 0.0000 4 135 2940 4500 1980 tcp-request connection {...}\001
+-6
+6 4635 3195 7425 3735
+6 4680 3420 7380 3600
+2 2 0 1 26 6 51 -1 20 0.000 0 0 -1 0 0 5
+ 4680 3420 7200 3420 7200 3600 4680 3600 4680 3420
+4 0 0 50 -1 14 10 0.0000 4 135 2625 4725 3555 monitor-net (mode=http) ?\001
+-6
+2 2 0 1 13 2 52 -1 20 0.000 0 0 -1 0 0 5
+ 4635 3195 7425 3195 7425 3735 4635 3735 4635 3195
+4 0 0 50 -1 14 10 0.0000 4 135 1575 4725 3330 http_init_txn()\001
+-6
+2 1 0 1 0 7 51 -1 -1 4.000 0 0 -1 1 0 3
+ 1 1 1.00 60.00 120.00
+ 6885 1710 7200 1710 7200 675
+2 1 0 1 0 7 51 -1 -1 4.000 0 0 -1 1 0 3
+ 1 1 1.00 60.00 120.00
+ 7290 1935 7425 1935 7425 675
+2 1 0 1 0 7 51 -1 -1 4.000 0 0 -1 1 0 3
+ 1 1 1.00 60.00 120.00
+ 5850 2340 7650 2340 7650 675
+2 1 0 1 0 7 51 -1 -1 4.000 0 0 -1 1 0 3
+ 1 1 1.00 60.00 120.00
+ 7200 3510 7875 3510 7875 675
+2 1 0 1 0 7 51 -1 -1 0.000 0 0 -1 0 0 2
+ 4140 675 4140 4275
+2 1 0 1 0 7 51 -1 -1 0.000 0 0 -1 0 0 2
+ 4320 1575 4320 4275
+2 1 0 1 0 7 51 -1 -1 4.000 0 0 -1 1 0 3
+ 1 1 1.00 60.00 120.00
+ 5580 1260 6750 1260 6750 675
+2 1 0 1 0 7 51 -1 -1 0.000 0 0 -1 0 0 2
+ 4545 2700 4545 4050
+2 1 0 1 0 7 51 -1 -1 4.000 0 0 -1 1 0 3
+ 1 1 1.00 60.00 120.00
+ 6345 1035 6525 1035 6525 675
+2 2 0 1 26 6 51 -1 20 0.000 0 0 -1 0 0 5
+ 4635 3825 6030 3825 6030 4005 4635 4005 4635 3825
+2 1 0 1 0 7 50 -1 -1 4.000 0 0 -1 0 0 3
+ 6030 3915 7875 3915 7875 3510
+2 2 0 1 26 6 51 -1 20 0.000 0 0 -1 0 0 5
+ 4230 720 5895 720 5895 900 4230 900 4230 720
+2 1 0 1 0 7 51 -1 -1 4.000 0 0 -1 1 0 3
+ 1 1 1.00 60.00 120.00
+ 5895 810 6300 810 6300 675
+4 1 0 51 -1 12 7 0.0000 4 60 375 7515 585 close\001
+4 1 0 51 -1 12 7 0.0000 4 75 1275 6930 2250 not enough memory\001
+4 0 0 51 -1 12 7 1.5708 4 60 1575 8010 2790 return "OK" and close\001
+4 0 0 50 -1 14 10 0.0000 4 135 1365 4275 1305 sock=accept()\001
+4 0 0 50 -1 14 10 0.0000 4 135 1890 4500 2655 frontend_accept(s)\001
+4 0 0 50 -1 14 10 0.0000 4 135 2100 4275 1530 session_accept(sock)\001
+4 0 0 50 -1 14 10 0.0000 4 105 1365 4500 2385 s=new session\001
+4 0 0 50 -1 14 10 0.0000 4 135 1575 4635 2880 prepare logs(s)\001
+4 0 0 50 -1 14 10 0.0000 4 135 2100 4635 3105 prepare socket(sock)\001
+4 0 0 50 -1 14 10 0.0000 4 105 1365 4680 3960 mode=health ?\001
+4 1 0 51 -1 12 7 0.0000 4 60 225 7605 3465 Yes\001
+4 1 0 51 -1 12 7 0.0000 4 60 225 7605 3870 Yes\001
+4 1 0 51 -1 12 7 0.0000 4 60 225 7065 1665 Yes\001
+4 1 0 51 -1 12 7 0.0000 4 75 300 6570 1215 Fail\001
+4 0 0 50 -1 14 10 0.0000 4 120 1680 4500 4230 start session(s)\001
+4 0 0 50 -1 14 10 0.0000 4 105 1785 4275 855 maxconn reached ?\001
+4 1 0 51 -1 12 7 0.0000 4 90 450 6525 585 ignore\001
+4 1 0 51 -1 12 7 0.0000 4 60 225 6120 765 Yes\001
+4 0 0 50 -1 17 12 0.0000 4 210 3000 450 630 Session instantiation sequence\001
+4 0 0 50 -1 14 10 0.0000 4 135 2100 4050 630 stream_sock_accept()\001
|
[-]
[+]
|
Changed |
haproxy-1.5.3.tar.gz/doc/proxy-protocol.txt
^
|
@@ -1,4 +1,4 @@
-2014/05/10 Willy Tarreau
+2014/07/25 Willy Tarreau
HAProxy Technologies
The PROXY protocol
Versions 1 & 2
@@ -19,6 +19,9 @@
2012/06/21 - add support for binary format
2012/11/19 - final review and fixes
2014/05/18 - modify and extend PROXY protocol version 2
+ 2014/06/11 - fix example code to consider ver+cmd merge
+ 2014/06/14 - fix v2 header check in example code, and update Forwarded spec
+ 2014/07/12 - update list of implementations (add Squid)
1. Background
@@ -27,11 +30,11 @@
original TCP connection parameters such as source and destination addresses,
ports, and so on. Some protocols make it a little bit easier to transfer such
information. For SMTP, Postfix authors have proposed the XCLIENT protocol [1]
-which received broad adoption and is particularly suited to mail exchanges. In
-HTTP, there is the "Forwarded-For" proposed standard [2]. This proposal aims at
-replacing the omnipresent "X-Forwarded-For" header which carries information
-about the original source address, and the less common X-Original-To which
-carries information about the destination address.
+which received broad adoption and is particularly suited to mail exchanges.
+For HTTP, there is the "Forwarded" extension [2], which aims at replacing the
+omnipresent "X-Forwarded-For" header which carries information about the
+original source address, and the less common X-Original-To which carries
+information about the destination address.
However, both mechanisms require a knowledge of the underlying protocol to be
implemented in intermediaries.
@@ -40,10 +43,11 @@
they don't do anything, but because they're processing protocol-agnostic data.
Both Stunnel[3] and Stud[4] are examples of such "dumb proxies". They talk raw
TCP on one side, and raw SSL on the other one, and do that reliably, without
-any knowledge of what protocol is transported on top of the connection.
+any knowledge of what protocol is transported on top of the connection. Haproxy
+running in pure TCP mode obviously falls into that category as well.
The problem with such a proxy when it is combined with another one such as
-haproxy is to adapt it to talk the higher level protocol. A patch is available
+haproxy, is to adapt it to talk the higher level protocol. A patch is available
for Stunnel to make it capable of inserting an X-Forwarded-For header in the
first HTTP request of each incoming connection. Haproxy is able not to add
another one when the connection comes from Stunnel, so that it's possible to
@@ -441,7 +445,7 @@
struct proxy_hdr_v2 {
uint8_t sig[12]; /* hex 0D 0A 0D 0A 00 0D 0A 51 55 49 54 0A */
- uint8_t ver; /* protocol version and command */
+ uint8_t ver_cmd; /* protocol version and command */
uint8_t fam; /* protocol family and address */
uint16_t len; /* number of following bytes part of the header */
};
@@ -552,6 +556,9 @@
Support for the protocol in the Varnish cache is being considered [6].
+Exim added support for version 1 and version 2 of the protocol for incoming
+connections on 2014/05/13, and will be released as part of version 4.83.
+
The protocol is simple enough that it is expected that other implementations
will appear, especially in environments such as SMTP, IMAP, FTP, RDP where the
client's address is an important piece of information for the server and some
@@ -686,6 +693,7 @@
- thttpd 2.20c : 400 Bad Request + abort => pass/optimal
- mini-httpd-1.19 : 400 Bad Request + abort => pass/optimal
- haproxy 1.4.21 : 400 Bad Request + abort => pass/optimal
+ - Squid 3 : 400 Bad Request + abort => pass/optimal
- SSL :
- stud 0.3.47 : connection abort => pass/optimal
- stunnel 4.45 : connection abort => pass/optimal
@@ -731,7 +739,7 @@
The following links were referenced in the document.
[1] http://www.postfix.org/XCLIENT_README.html
-[2] http://tools.ietf.org/html/draft-ietf-appsawg-http-forwarded
+[2] http://tools.ietf.org/html/rfc7239
[3] http://www.stunnel.org/
[4] https://github.com/bumptech/stud
[5] https://github.com/bumptech/stud/pull/81
@@ -748,7 +756,7 @@
struct sockaddr_storage from; /* already filled by accept() */
struct sockaddr_storage to; /* already filled by getsockname() */
- const char v2sig[13] = "\x0D\x0A\x0D\x0A\x00\x0D\x0A\x51\x55\x49\x54\x0A\x02";
+ const char v2sig[12] = "\x0D\x0A\x0D\x0A\x00\x0D\x0A\x51\x55\x49\x54\x0A";
/* returns 0 if needs to poll, <0 upon error or >0 if it did the job */
int read_evt(int fd)
@@ -759,10 +767,9 @@
} v1;
struct {
uint8_t sig[12];
- uint8_t ver;
- uint8_t cmd;
+ uint8_t ver_cmd;
uint8_t fam;
- uint8_t len;
+ uint16_t len;
union {
struct { /* for TCP/UDP over IPv4, len = 12 */
uint32_t src_addr;
@@ -793,12 +800,13 @@
if (ret == -1)
return (errno == EAGAIN) ? 0 : -1;
- if (ret >= 16 && memcmp(&hdr.v2, v2sig, 13) == 0) {
+ if (ret >= 16 && memcmp(&hdr.v2, v2sig, 12) == 0 &&
+ (hdr.v2.ver_cmd & 0xF0) == 0x20) {
size = 16 + hdr.v2.len;
if (ret < size)
return -1; /* truncated or too large header */
- switch (hdr.v2.cmd) {
+ switch (hdr.v2.ver_cmd & 0xF) {
case 0x01: /* PROXY command */
switch (hdr.v2.fam) {
case 0x11: /* TCPv4 */
|
[-]
[+]
|
Changed |
haproxy-1.5.3.tar.gz/examples/haproxy.spec
^
|
@@ -1,6 +1,6 @@
Summary: HA-Proxy is a TCP/HTTP reverse proxy for high availability environments
Name: haproxy
-Version: 1.5-dev26
+Version: 1.5.3
Release: 1
License: GPL
Group: System Environment/Daemons
@@ -67,7 +67,7 @@
%files
%defattr(-,root,root)
-%doc CHANGELOG TODO examples/*.cfg doc/haproxy-en.txt doc/haproxy-fr.txt doc/architecture.txt doc/configuration.txt
+%doc CHANGELOG README examples/*.cfg doc/haproxy-en.txt doc/haproxy-fr.txt doc/architecture.txt doc/configuration.txt doc/proxy-protocol.txt
%doc %{_mandir}/man1/%{name}.1*
%attr(0755,root,root) %{_sbindir}/%{name}
@@ -76,6 +76,18 @@
%attr(0755,root,root) %config %{_sysconfdir}/rc.d/init.d/%{name}
%changelog
+* Fri Jul 25 2014 Willy Tarreau <w@1wt.eu>
+- updated to 1.5.3
+
+* Sat Jul 12 2014 Willy Tarreau <w@1wt.eu>
+- updated to 1.5.2
+
+* Tue Jun 24 2014 Willy Tarreau <w@1wt.eu>
+- updated to 1.5.1
+
+* Thu Jun 19 2014 Willy Tarreau <w@1wt.eu>
+- updated to 1.5.0
+
* Wed May 28 2014 Willy Tarreau <w@1wt.eu>
- updated to 1.5-dev26
|
[-]
[+]
|
Changed |
haproxy-1.5.3.tar.gz/include/common/defaults.h
^
|
@@ -48,6 +48,10 @@
#define CAPTURE_LEN 64
#endif
+#ifndef MAX_SYSLOG_LEN
+#define MAX_SYSLOG_LEN 1024
+#endif
+
// maximum line size when parsing config
#ifndef LINESIZE
#define LINESIZE 2048
@@ -214,4 +218,28 @@
#define SSLCACHESIZE 20000
#endif
+/* ssl max dh param size */
+#ifndef SSL_DEFAULT_DH_PARAM
+#define SSL_DEFAULT_DH_PARAM 0
+#endif
+
+/* Number of samples used to compute the times reported in stats. A power of
+ * two is highly recommended, and this value multiplied by the largest response
+ * time must not overflow and unsigned int. See freq_ctr.h for more information.
+ * We consider that values are accurate to 95% with two batches of samples below,
+ * so in order to advertise accurate times across 1k samples, we effectively
+ * measure over 512.
+ */
+#ifndef TIME_STATS_SAMPLES
+#define TIME_STATS_SAMPLES 512
+#endif
+
+/* max ocsp cert id asn1 encoded length */
+#ifndef OCSP_MAX_CERTID_ASN1_LENGTH
+#define OCSP_MAX_CERTID_ASN1_LENGTH 128
+#endif
+
+#ifndef OCSP_MAX_RESPONSE_TIME_SKEW
+#define OCSP_MAX_RESPONSE_TIME_SKEW 300
+#endif
#endif /* _COMMON_DEFAULTS_H */
|
[-]
[+]
|
Changed |
haproxy-1.5.3.tar.gz/include/common/hash.h
^
|
@@ -22,8 +22,8 @@
#ifndef _COMMON_HASH_H_
#define _COMMON_HASH_H_
-unsigned long hash_djb2(const char *key, int len);
-unsigned long hash_wt6(const char *key, int len);
-unsigned long hash_sdbm(const char *key, int len);
+unsigned int hash_djb2(const char *key, int len);
+unsigned int hash_wt6(const char *key, int len);
+unsigned int hash_sdbm(const char *key, int len);
#endif /* _COMMON_HASH_H_ */
|
[-]
[+]
|
Changed |
haproxy-1.5.3.tar.gz/include/common/regex.h
^
|
@@ -35,14 +35,12 @@
struct my_regex {
#ifdef USE_PCRE
+ pcre *reg;
+ pcre_extra *extra;
#ifdef USE_PCRE_JIT
#ifndef PCRE_CONFIG_JIT
#error "The PCRE lib doesn't support JIT. Change your lib, or remove the option USE_PCRE_JIT."
#endif
- pcre *reg;
- pcre_extra *extra;
-#else /* no PCRE_JIT */
- regex_t regex;
#endif
#else /* no PCRE */
regex_t regex;
@@ -60,7 +58,7 @@
struct hdr_exp {
struct hdr_exp *next;
- const regex_t *preg; /* expression to look for */
+ struct my_regex *preg; /* expression to look for */
int action; /* ACT_ALLOW, ACT_REPLACE, ACT_REMOVE, ACT_DENY */
const char *replace; /* expression to set instead */
void *cond; /* a possible condition or NULL */
@@ -79,32 +77,61 @@
* The function return 1 is succes case, else return 0 and err is filled.
*/
int regex_comp(const char *str, struct my_regex *regex, int cs, int cap, char **err);
-int exp_replace(char *dst, uint dst_size, char *src, const char *str, const regmatch_t *matches);
+int exp_replace(char *dst, unsigned int dst_size, char *src, const char *str, const regmatch_t *matches);
const char *check_replace_string(const char *str);
-const char *chain_regex(struct hdr_exp **head, const regex_t *preg,
+const char *chain_regex(struct hdr_exp **head, struct my_regex *preg,
int action, const char *replace, void *cond);
+/* If the function doesn't match, it returns false, else it returns true.
+ */
+static inline int regex_exec(const struct my_regex *preg, char *subject) {
+#if defined(USE_PCRE) || defined(USE_PCRE_JIT)
+ if (pcre_exec(preg->reg, preg->extra, subject, strlen(subject), 0, 0, NULL, 0) < 0)
+ return 0;
+ return 1;
+#else
+ int match;
+ match = regexec(&preg->regex, subject, 0, NULL, 0);
+ if (match == REG_NOMATCH)
+ return 0;
+ return 1;
+#endif
+}
+
/* Note that <subject> MUST be at least <length+1> characters long and must
* be writable because the function will temporarily force a zero past the
* last character.
+ *
+ * If the function doesn't match, it returns false, else it returns true.
*/
-static inline int regex_exec(const struct my_regex *preg, char *subject, int length) {
-#ifdef USE_PCRE_JIT
- return pcre_exec(preg->reg, preg->extra, subject, length, 0, 0, NULL, 0);
+static inline int regex_exec2(const struct my_regex *preg, char *subject, int length) {
+#if defined(USE_PCRE) || defined(USE_PCRE_JIT)
+ if (pcre_exec(preg->reg, preg->extra, subject, length, 0, 0, NULL, 0) < 0)
+ return 0;
+ return 1;
#else
int match;
char old_char = subject[length];
subject[length] = 0;
match = regexec(&preg->regex, subject, 0, NULL, 0);
subject[length] = old_char;
- return match;
+ if (match == REG_NOMATCH)
+ return 0;
+ return 1;
#endif
}
+int regex_exec_match(const struct my_regex *preg, const char *subject,
+ size_t nmatch, regmatch_t pmatch[]);
+int regex_exec_match2(const struct my_regex *preg, char *subject, int length,
+ size_t nmatch, regmatch_t pmatch[]);
+
static inline void regex_free(struct my_regex *preg) {
+#if defined(USE_PCRE) || defined(USE_PCRE_JIT)
+ pcre_free(preg->reg);
#ifdef USE_PCRE_JIT
pcre_free_study(preg->extra);
- pcre_free(preg->reg);
+#endif
#else
regfree(&preg->regex);
#endif
|
[-]
[+]
|
Changed |
haproxy-1.5.3.tar.gz/include/common/standard.h
^
|
@@ -52,6 +52,10 @@
/* number of itoa_str entries */
#define NB_ITOA_STR 10
+/* maximum quoted string length (truncated above) */
+#define QSTR_SIZE 200
+#define NB_QSTR 10
+
/****** string-specific macros and functions ******/
/* if a > max, then bound <a> to <max>. The macro returns the new <a> */
#define UBOUND(a, max) ({ typeof(a) b = (max); if ((a) > b) (a) = b; (a); })
@@ -195,6 +199,29 @@
return ret;
}
+/* returns a locally allocated string containing the quoted encoding of the
+ * input string. The output may be truncated to QSTR_SIZE chars, but it is
+ * guaranteed that the string will always be properly terminated. Quotes are
+ * encoded by doubling them as is commonly done in CSV files. QSTR_SIZE must
+ * always be at least 4 chars.
+ */
+const char *qstr(const char *str);
+
+/* returns <str> or its quote-encoded equivalent if it contains at least one
+ * quote or a comma. This is aimed at build CSV-compatible strings.
+ */
+static inline const char *cstr(const char *str)
+{
+ const char *p = str;
+
+ while (*p) {
+ if (*p == ',' || *p == '"')
+ return qstr(str);
+ p++;
+ }
+ return str;
+}
+
/*
* Returns non-zero if character <s> is a hex digit (0-9, a-f, A-F), else zero.
*/
@@ -291,6 +318,14 @@
*/
int addr_to_str(struct sockaddr_storage *addr, char *str, int size);
+/* Tries to convert a sockaddr_storage port to text form. Upon success, the
+ * address family is returned so that it's easy for the caller to adapt to the
+ * output format. Zero is returned if the address family is not supported. -1
+ * is returned upon error, with errno set. AF_INET, AF_INET6 and AF_UNIX are
+ * supported.
+ */
+int port_to_str(struct sockaddr_storage *addr, char *str, int size);
+
/* will try to encode the string <string> replacing all characters tagged in
* <map> with the hexadecimal representation of their ASCII-code (2 digits)
* prefixed by <escape>, and will store the result between <start> (included)
|
[-]
[+]
|
Changed |
haproxy-1.5.3.tar.gz/include/proto/freq_ctr.h
^
|
@@ -1,23 +1,23 @@
/*
- include/proto/freq_ctr.h
- This file contains macros and inline functions for frequency counters.
-
- Copyright (C) 2000-2009 Willy Tarreau - w@1wt.eu
-
- This library is free software; you can redistribute it and/or
- modify it under the terms of the GNU Lesser General Public
- License as published by the Free Software Foundation, version 2.1
- exclusively.
-
- This library 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
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public
- License along with this library; if not, write to the Free Software
- Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
-*/
+ * include/proto/freq_ctr.h
+ * This file contains macros and inline functions for frequency counters.
+ *
+ * Copyright (C) 2000-2014 Willy Tarreau - w@1wt.eu
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, version 2.1
+ * exclusively.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
#ifndef _PROTO_FREQ_CTR_H
#define _PROTO_FREQ_CTR_H
@@ -115,6 +115,123 @@
unsigned int freq_ctr_remain_period(struct freq_ctr_period *ctr, unsigned int period,
unsigned int freq, unsigned int pend);
+/* While the functions above report average event counts per period, we are
+ * also interested in average values per event. For this we use a different
+ * method. The principle is to rely on a long tail which sums the new value
+ * with a fraction of the previous value, resulting in a sliding window of
+ * infinite length depending on the precision we're interested in.
+ *
+ * The idea is that we always keep (N-1)/N of the sum and add the new sampled
+ * value. The sum over N values can be computed with a simple program for a
+ * constant value 1 at each iteration :
+ *
+ * N
+ * ,---
+ * \ N - 1 e - 1
+ * > ( --------- )^x ~= N * -----
+ * / N e
+ * '---
+ * x = 1
+ *
+ * Note: I'm not sure how to demonstrate this but at least this is easily
+ * verified with a simple program, the sum equals N * 0.632120 for any N
+ * moderately large (tens to hundreds).
+ *
+ * Inserting a constant sample value V here simply results in :
+ *
+ * sum = V * N * (e - 1) / e
+ *
+ * But we don't want to integrate over a small period, but infinitely. Let's
+ * cut the infinity in P periods of N values. Each period M is exactly the same
+ * as period M-1 with a factor of ((N-1)/N)^N applied. A test shows that given a
+ * large N :
+ *
+ * N - 1 1
+ * ( ------- )^N ~= ---
+ * N e
+ *
+ * Our sum is now a sum of each factor times :
+ *
+ * N*P P
+ * ,--- ,---
+ * \ N - 1 e - 1 \ 1
+ * > v ( --------- )^x ~= VN * ----- * > ---
+ * / N e / e^x
+ * '--- '---
+ * x = 1 x = 0
+ *
+ * For P "large enough", in tests we get this :
+ *
+ * P
+ * ,---
+ * \ 1 e
+ * > --- ~= -----
+ * / e^x e - 1
+ * '---
+ * x = 0
+ *
+ * This simplifies the sum above :
+ *
+ * N*P
+ * ,---
+ * \ N - 1
+ * > v ( --------- )^x = VN
+ * / N
+ * '---
+ * x = 1
+ *
+ * So basically by summing values and applying the last result an (N-1)/N factor
+ * we just get N times the values over the long term, so we can recover the
+ * constant value V by dividing by N.
+ *
+ * A value added at the entry of the sliding window of N values will thus be
+ * reduced to 1/e or 36.7% after N terms have been added. After a second batch,
+ * it will only be 1/e^2, or 13.5%, and so on. So practically speaking, each
+ * old period of N values represents only a quickly fading ratio of the global
+ * sum :
+ *
+ * period ratio
+ * 1 36.7%
+ * 2 13.5%
+ * 3 4.98%
+ * 4 1.83%
+ * 5 0.67%
+ * 6 0.25%
+ * 7 0.09%
+ * 8 0.033%
+ * 9 0.012%
+ * 10 0.0045%
+ *
+ * So after 10N samples, the initial value has already faded out by a factor of
+ * 22026, which is quite fast. If the sliding window is 1024 samples wide, it
+ * means that a sample will only count for 1/22k of its initial value after 10k
+ * samples went after it, which results in half of the value it would represent
+ * using an arithmetic mean. The benefit of this method is that it's very cheap
+ * in terms of computations when N is a power of two. This is very well suited
+ * to record response times as large values will fade out faster than with an
+ * arithmetic mean and will depend on sample count and not time.
+ *
+ * Demonstrating all the above assumptions with maths instead of a program is
+ * left as an exercise for the reader.
+ */
+
+/* Adds sample value <v> to sliding window sum <sum> configured for <n> samples.
+ * The sample is returned. Better if <n> is a power of two.
+ */
+static inline unsigned int swrate_add(unsigned int *sum, unsigned int n, unsigned int v)
+{
+ return *sum = *sum * (n - 1) / n + v;
+}
+
+/* Returns the average sample value for the sum <sum> over a sliding window of
+ * <n> samples. Better if <n> is a power of two. It must be the same <n> as the
+ * one used above in all additions.
+ */
+static inline unsigned int swrate_avg(unsigned int sum, unsigned int n)
+{
+ return (sum + n - 1) / n;
+}
+
#endif /* _PROTO_FREQ_CTR_H */
/*
|
[-]
[+]
|
Changed |
haproxy-1.5.3.tar.gz/include/proto/log.h
^
|
@@ -39,6 +39,7 @@
extern char default_tcp_log_format[];
extern char default_http_log_format[];
extern char clf_http_log_format[];
+extern char *logline;
int build_logline(struct session *s, char *dst, size_t maxsize, struct list *list_format);
|
[-]
[+]
|
Changed |
haproxy-1.5.3.tar.gz/include/proto/proto_http.h
^
|
@@ -116,6 +116,7 @@
struct http_req_rule *parse_http_req_cond(const char **args, const char *file, int linenum, struct proxy *proxy);
struct http_res_rule *parse_http_res_cond(const char **args, const char *file, int linenum, struct proxy *proxy);
void free_http_req_rules(struct list *r);
+void free_http_res_rules(struct list *r);
struct chunk *http_error_message(struct session *s, int msgnum);
struct redirect_rule *http_parse_redirect_rule(const char *file, int linenum, struct proxy *curproxy,
const char **args, char **errmsg, int use_fmt);
|
[-]
[+]
|
Changed |
haproxy-1.5.3.tar.gz/include/proto/proto_tcp.h
^
|
@@ -30,6 +30,7 @@
int tcp_bind_socket(int fd, int flags, struct sockaddr_storage *local, struct sockaddr_storage *remote);
void tcpv4_add_listener(struct listener *listener);
void tcpv6_add_listener(struct listener *listener);
+int tcp_pause_listener(struct listener *l);
int tcp_connect_server(struct connection *conn, int data, int delack);
int tcp_connect_probe(struct connection *conn);
int tcp_get_src(int fd, struct sockaddr *sa, socklen_t salen, int dir);
|
[-]
[+]
|
Changed |
haproxy-1.5.3.tar.gz/include/proto/proto_uxst.h
^
|
@@ -27,6 +27,7 @@
#include <types/task.h>
void uxst_add_listener(struct listener *listener);
+int uxst_pause_listener(struct listener *l);
int uxst_get_src(int fd, struct sockaddr *sa, socklen_t salen, int dir);
int uxst_get_dst(int fd, struct sockaddr *sa, socklen_t salen, int dir);
|
[-]
[+]
|
Changed |
haproxy-1.5.3.tar.gz/include/proto/session.h
^
|
@@ -50,6 +50,9 @@
struct track_ctr_prm *prm,
struct proxy *defpx, char **err);
+/* Update the session's backend and server time stats */
+void session_update_time_stats(struct session *s);
+
/* returns the session from a void *owner */
static inline struct session *session_from_task(struct task *t)
{
|
[-]
[+]
|
Changed |
haproxy-1.5.3.tar.gz/include/proto/ssl_sock.h
^
|
@@ -52,8 +52,11 @@
const char *ssl_sock_get_proto_version(struct connection *conn);
char *ssl_sock_get_version(struct connection *conn);
int ssl_sock_get_cert_used(struct connection *conn);
-char *ssl_sock_get_common_name(struct connection *conn);
+int ssl_sock_get_remote_common_name(struct connection *conn, struct chunk *out);
unsigned int ssl_sock_get_verify_result(struct connection *conn);
+#ifdef SSL_CTRL_SET_TLSEXT_STATUS_REQ_CB
+int ssl_sock_update_ocsp_response(struct chunk *ocsp_response, char **err);
+#endif
#endif /* _PROTO_SSL_SOCK_H */
|
[-]
[+]
|
Changed |
haproxy-1.5.3.tar.gz/include/proto/stick_table.h
^
|
@@ -48,7 +48,7 @@
struct stksess *stktable_update_key(struct stktable *table, struct stktable_key *key);
struct stktable_key *stktable_fetch_key(struct stktable *t, struct proxy *px,
struct session *l4, void *l7, unsigned int opt,
- struct sample_expr *expr);
+ struct sample_expr *expr, struct sample *smp);
int stktable_compatible_sample(struct sample_expr *expr, unsigned long table_type);
int stktable_get_data_type(char *name);
struct proxy *find_stktable(const char *name);
|
[-]
[+]
|
Changed |
haproxy-1.5.3.tar.gz/include/types/arg.h
^
|
@@ -58,6 +58,7 @@
ARGC_HRS, /* http-response */
ARGC_UIF, /* unique-id-format */
ARGC_RDR, /* redirect */
+ ARGC_CAP, /* capture rule */
};
/* some types that are externally defined */
|
[-]
[+]
|
Changed |
haproxy-1.5.3.tar.gz/include/types/capture.h
^
|
@@ -27,8 +27,8 @@
struct cap_hdr {
struct cap_hdr *next;
- char *name; /* header name, case insensitive */
- int namelen; /* length of the header name, to speed-up lookups */
+ char *name; /* header name, case insensitive, NULL if not header */
+ int namelen; /* length of the header name, to speed-up lookups, 0 if !name */
int len; /* capture length, not including terminal zero */
int index; /* index in the output array */
struct pool_head *pool; /* pool of pre-allocated memory area of (len+1) bytes */
|
[-]
[+]
|
Changed |
haproxy-1.5.3.tar.gz/include/types/checks.h
^
|
@@ -177,7 +177,7 @@
/* sent string is string */
char *string; /* sent or expected string */
int string_len; /* string lenght */
- regex_t *expect_regex; /* expected */
+ struct my_regex *expect_regex; /* expected */
int inverse; /* 0 = regular match, 1 = inverse match */
unsigned short port; /* port to connect to */
unsigned short conn_opts; /* options when setting up a new connection */
|
[-]
[+]
|
Changed |
haproxy-1.5.3.tar.gz/include/types/connection.h
^
|
@@ -268,53 +268,63 @@
};
/* proxy protocol v2 definitions */
-#define PP2_SIGNATURE_LEN 12
-#define PP2_HEADER_LEN 16
-#define PP2_VERSION 0x20
-#define PP2_CMD_LOCAL 0x00
-#define PP2_CMD_PROXY 0x01
-#define PP2_FAM_UNSPEC 0x00
-#define PP2_FAM_INET 0x10
-#define PP2_FAM_INET6 0x20
-#define PP2_FAM_UNIX 0x30
-#define PP2_TRANS_UNSPEC 0x00
-#define PP2_TRANS_STREAM 0x01
-#define PP2_TRANS_DGRAM 0x02
-
-#define PP2_ADDR_LEN_UNSPEC 0
-#define PP2_ADDR_LEN_INET 12
-#define PP2_ADDR_LEN_INET6 36
-#define PP2_ADDR_LEN_UNIX 216
-
-#define PP2_HDR_LEN_UNSPEC (PP2_HEADER_LEN + PP2_ADDR_LEN_UNSPEC)
-#define PP2_HDR_LEN_INET (PP2_HEADER_LEN + PP2_ADDR_LEN_INET)
-#define PP2_HDR_LEN_INET6 (PP2_HEADER_LEN + PP2_ADDR_LEN_INET6)
-#define PP2_HDR_LEN_UNIX (PP2_HEADER_LEN + PP2_ADDR_LEN_UNIX)
+#define PP2_SIGNATURE "\x0D\x0A\x0D\x0A\x00\x0D\x0A\x51\x55\x49\x54\x0A"
+#define PP2_SIGNATURE_LEN 12
+#define PP2_HEADER_LEN 16
+
+/* ver_cmd byte */
+#define PP2_CMD_LOCAL 0x00
+#define PP2_CMD_PROXY 0x01
+#define PP2_CMD_MASK 0x0F
+
+#define PP2_VERSION 0x20
+#define PP2_VERSION_MASK 0xF0
+
+/* fam byte */
+#define PP2_TRANS_UNSPEC 0x00
+#define PP2_TRANS_STREAM 0x01
+#define PP2_TRANS_DGRAM 0x02
+#define PP2_TRANS_MASK 0x0F
+
+#define PP2_FAM_UNSPEC 0x00
+#define PP2_FAM_INET 0x10
+#define PP2_FAM_INET6 0x20
+#define PP2_FAM_UNIX 0x30
+#define PP2_FAM_MASK 0xF0
+
+#define PP2_ADDR_LEN_UNSPEC (0)
+#define PP2_ADDR_LEN_INET (4 + 4 + 2 + 2)
+#define PP2_ADDR_LEN_INET6 (16 + 16 + 2 + 2)
+#define PP2_ADDR_LEN_UNIX (108 + 108)
+
+#define PP2_HDR_LEN_UNSPEC (PP2_HEADER_LEN + PP2_ADDR_LEN_UNSPEC)
+#define PP2_HDR_LEN_INET (PP2_HEADER_LEN + PP2_ADDR_LEN_INET)
+#define PP2_HDR_LEN_INET6 (PP2_HEADER_LEN + PP2_ADDR_LEN_INET6)
+#define PP2_HDR_LEN_UNIX (PP2_HEADER_LEN + PP2_ADDR_LEN_UNIX)
struct proxy_hdr_v2 {
uint8_t sig[12]; /* hex 0D 0A 0D 0A 00 0D 0A 51 55 49 54 0A */
- uint8_t cmd; /* protocol version and command */
+ uint8_t ver_cmd; /* protocol version and command */
uint8_t fam; /* protocol family and transport */
uint16_t len; /* number of following bytes part of the header */
-};
-
-union proxy_addr {
- struct { /* for TCP/UDP over IPv4, len = 12 */
- uint32_t src_addr;
- uint32_t dst_addr;
- uint16_t src_port;
- uint16_t dst_port;
- } ipv4_addr;
- struct { /* for TCP/UDP over IPv6, len = 36 */
- uint8_t src_addr[16];
- uint8_t dst_addr[16];
- uint16_t src_port;
- uint16_t dst_port;
- } ipv6_addr;
- struct { /* for AF_UNIX sockets, len = 216 */
- uint8_t src_addr[108];
- uint8_t dst_addr[108];
- } unix_addr;
+ union {
+ struct { /* for TCP/UDP over IPv4, len = 12 */
+ uint32_t src_addr;
+ uint32_t dst_addr;
+ uint16_t src_port;
+ uint16_t dst_port;
+ } ip4;
+ struct { /* for TCP/UDP over IPv6, len = 36 */
+ uint8_t src_addr[16];
+ uint8_t dst_addr[16];
+ uint16_t src_port;
+ uint16_t dst_port;
+ } ip6;
+ struct { /* for AF_UNIX sockets, len = 216 */
+ uint8_t src_addr[108];
+ uint8_t dst_addr[108];
+ } unx;
+ } addr;
};
#define PP2_TYPE_SSL 0x20
|
[-]
[+]
|
Changed |
haproxy-1.5.3.tar.gz/include/types/counters.h
^
|
@@ -3,7 +3,7 @@
* This file contains structure declarations for statistics counters.
*
* Copyright 2008-2009 Krzysztof Piotr Oledzki <ole@ans.pl>
- * Copyright 2011 Willy Tarreau <w@1wt.eu>
+ * Copyright 2011-2014 Willy Tarreau <w@1wt.eu>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -55,6 +55,8 @@
long long redispatches; /* retried and redispatched connections (BE only) */
long long intercepted_req; /* number of monitoring or stats requests intercepted by the frontend */
+ unsigned int q_time, c_time, d_time, t_time; /* sums of conn_time, queue_time, data_time, total_time */
+
union {
struct {
long long cum_req; /* cumulated number of processed HTTP requests */
@@ -96,6 +98,8 @@
long long retries, redispatches; /* retried and redispatched connections */
long long failed_secu; /* blocked responses because of security concerns */
+ unsigned int q_time, c_time, d_time, t_time; /* sums of conn_time, queue_time, data_time, total_time */
+
union {
struct {
long long rsp[6]; /* http response codes */
|
[-]
[+]
|
Changed |
haproxy-1.5.3.tar.gz/include/types/global.h
^
|
@@ -110,6 +110,7 @@
int last_checks;
int spread_checks;
int max_spread_checks;
+ int max_syslog_len;
char *chroot;
char *pidfile;
char *node, *desc; /* node name & description */
@@ -136,6 +137,7 @@
int sslprivatecache; /* Force to use a private session cache even if nbproc > 1 */
unsigned int ssllifetime; /* SSL session lifetime in seconds */
unsigned int ssl_max_record; /* SSL max record size */
+ unsigned int ssl_default_dh_param; /* SSL maximum DH parameter size */
#endif
#ifdef USE_ZLIB
int zlibmemlevel; /* zlib memlevel */
|
[-]
[+]
|
Changed |
haproxy-1.5.3.tar.gz/include/types/log.h
^
|
@@ -28,7 +28,6 @@
#include <common/config.h>
#include <common/mini-clist.h>
-#define MAX_SYSLOG_LEN 1024
#define NB_LOG_FACILITIES 24
#define NB_LOG_LEVELS 8
#define SYSLOG_PORT 514
@@ -153,6 +152,7 @@
int facility;
int level;
int minlvl;
+ int maxlen;
};
#endif /* _TYPES_LOG_H */
|
[-]
[+]
|
Changed |
haproxy-1.5.3.tar.gz/include/types/proto_http.h
^
|
@@ -25,6 +25,7 @@
#include <common/chunk.h>
#include <common/config.h>
#include <common/mini-clist.h>
+#include <common/regex.h>
#include <types/hdr_idx.h>
@@ -247,6 +248,8 @@
HTTP_REQ_ACT_ADD_HDR,
HTTP_REQ_ACT_SET_HDR,
HTTP_REQ_ACT_DEL_HDR,
+ HTTP_REQ_ACT_REPLACE_HDR,
+ HTTP_REQ_ACT_REPLACE_VAL,
HTTP_REQ_ACT_REDIR,
HTTP_REQ_ACT_SET_NICE,
HTTP_REQ_ACT_SET_LOGL,
@@ -267,6 +270,8 @@
HTTP_RES_ACT_ALLOW,
HTTP_RES_ACT_DENY,
HTTP_RES_ACT_ADD_HDR,
+ HTTP_RES_ACT_REPLACE_HDR,
+ HTTP_RES_ACT_REPLACE_VAL,
HTTP_RES_ACT_SET_HDR,
HTTP_RES_ACT_DEL_HDR,
HTTP_RES_ACT_SET_NICE,
@@ -324,7 +329,8 @@
* message or a response message.
*
* The values there are a little bit obscure, because their meaning can change
- * during the parsing :
+ * during the parsing. Please read carefully doc/internal/body-parsing.txt if
+ * you need to manipulate them. Quick reminder :
*
* - eoh (End of Headers) : relative offset in the buffer of first byte that
* is not part of a completely processed header.
@@ -339,9 +345,9 @@
* - sov (start of value) : Before HTTP_MSG_BODY, points to the value of
* the header being parsed. Starting from
* HTTP_MSG_BODY, will point to the start of the
- * body (relative to buffer's origin), or to data
- * following a chunk size. Thus <sov> bytes of
- * headers will have to be sent only once.
+ * body (relative to buffer's origin). It can be
+ * negative when forwarding data. It stops growing
+ * once data start to leave the buffer.
*
* - next (parse pointer) : next relative byte to be parsed. Always points
* to a byte matching the current state.
@@ -367,7 +373,7 @@
/* 6 bytes unused here */
struct channel *chn; /* pointer to the channel transporting the message */
unsigned int next; /* pointer to next byte to parse, relative to buf->p */
- unsigned int sov; /* current header: start of value */
+ int sov; /* current header: start of value ; data: start of body */
unsigned int eoh; /* End Of Headers, relative to buffer */
unsigned int sol; /* start of current line during parsing otherwise zero */
unsigned int eol; /* end of line */
@@ -415,6 +421,7 @@
char *name; /* header name */
int name_len; /* header name's length */
struct list fmt; /* log-format compatible expression */
+ struct my_regex re; /* used by replace-header and replace-value */
} hdr_add; /* args used by "add-header" and "set-header" */
struct redirect_rule *redir; /* redirect rule or "http-request redirect" */
int nice; /* nice value for HTTP_REQ_ACT_SET_NICE */
@@ -440,6 +447,7 @@
char *name; /* header name */
int name_len; /* header name's length */
struct list fmt; /* log-format compatible expression */
+ struct my_regex re; /* used by replace-header and replace-value */
} hdr_add; /* args used by "add-header" and "set-header" */
int nice; /* nice value for HTTP_RES_ACT_SET_NICE */
int loglevel; /* log-level value for HTTP_RES_ACT_SET_LOGL */
|
[-]
[+]
|
Changed |
haproxy-1.5.3.tar.gz/include/types/proto_tcp.h
^
|
@@ -38,6 +38,12 @@
TCP_ACT_TRK_SC2 = 6,
TCP_ACT_TRK_SCMAX = TCP_ACT_TRK_SC0 + MAX_SESS_STKCTR - 1,
TCP_ACT_CLOSE, /* close at the sender's */
+ TCP_ACT_CAPTURE, /* capture a fetched sample */
+};
+
+struct capture_prm {
+ struct sample_expr *expr; /* expression used as the key */
+ struct cap_hdr *hdr; /* the capture storage */
};
struct tcp_rule {
@@ -46,6 +52,7 @@
int action;
union {
struct track_ctr_prm trk_ctr;
+ struct capture_prm cap;
} act_prm;
};
|
[-]
[+]
|
Changed |
haproxy-1.5.3.tar.gz/include/types/protocol.h
^
|
@@ -60,6 +60,7 @@
int (*get_src)(int fd, struct sockaddr *, socklen_t, int dir); /* syscall used to retrieve src addr */
int (*get_dst)(int fd, struct sockaddr *, socklen_t, int dir); /* syscall used to retrieve dst addr */
int (*drain)(int fd); /* indicates whether we can safely close the fd */
+ int (*pause)(struct listener *l); /* temporarily pause this listener for a soft restart */
struct list listeners; /* list of listeners using this protocol */
int nb_listeners; /* number of listeners */
|
[-]
[+]
|
Changed |
haproxy-1.5.3.tar.gz/include/types/proxy.h
^
|
@@ -343,7 +343,7 @@
char *check_req; /* HTTP or SSL request to use for PR_O_HTTP_CHK|PR_O_SSL3_CHK */
int check_len; /* Length of the HTTP or SSL3 request */
char *expect_str; /* http-check expected content : string or text version of the regex */
- regex_t *expect_regex; /* http-check expected content */
+ struct my_regex *expect_regex; /* http-check expected content */
struct chunk errmsg[HTTP_ERR_SIZE]; /* default or customized error messages for known errors */
int uuid; /* universally unique proxy ID, used for SNMP */
unsigned int backlog; /* force the frontend's listen backlog */
|
[-]
[+]
|
Changed |
haproxy-1.5.3.tar.gz/src/backend.c
^
|
@@ -63,9 +63,9 @@
}
/* helper function to invoke the correct hash method */
-static unsigned long gen_hash(const struct proxy* px, const char* key, unsigned long len)
+static unsigned int gen_hash(const struct proxy* px, const char* key, unsigned long len)
{
- unsigned long hash;
+ unsigned int hash;
switch (px->lbprm.algo & BE_LB_HASH_FUNC) {
case BE_LB_HFCN_DJB2:
@@ -183,7 +183,7 @@
*/
struct server *get_server_uh(struct proxy *px, char *uri, int uri_len)
{
- unsigned long hash = 0;
+ unsigned int hash = 0;
int c;
int slashes = 0;
const char *start, *end;
@@ -232,7 +232,7 @@
*/
struct server *get_server_ph(struct proxy *px, const char *uri, int uri_len)
{
- unsigned long hash = 0;
+ unsigned int hash = 0;
const char *start, *end;
const char *p;
const char *params;
@@ -294,7 +294,7 @@
*/
struct server *get_server_ph_post(struct session *s)
{
- unsigned long hash = 0;
+ unsigned int hash = 0;
struct http_txn *txn = &s->txn;
struct channel *req = s->req;
struct http_msg *msg = &txn->req;
@@ -372,7 +372,7 @@
*/
struct server *get_server_hh(struct session *s)
{
- unsigned long hash = 0;
+ unsigned int hash = 0;
struct http_txn *txn = &s->txn;
struct proxy *px = s->be;
unsigned int plen = px->hh_len;
@@ -444,7 +444,7 @@
/* RDP Cookie HASH. */
struct server *get_server_rch(struct session *s)
{
- unsigned long hash = 0;
+ unsigned int hash = 0;
struct proxy *px = s->be;
unsigned long len;
int ret;
|
[-]
[+]
|
Changed |
haproxy-1.5.3.tar.gz/src/cfgparse.c
^
|
@@ -633,6 +633,19 @@
}
global.tune.ssl_max_record = atol(args[1]);
}
+ else if (!strcmp(args[0], "tune.ssl.default-dh-param")) {
+ if (*(args[1]) == 0) {
+ Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
+ err_code |= ERR_ALERT | ERR_FATAL;
+ goto out;
+ }
+ global.tune.ssl_default_dh_param = atol(args[1]);
+ if (global.tune.ssl_default_dh_param < 1024) {
+ Alert("parsing [%s:%d] : '%s' expects a value >= 1024.\n", file, linenum, args[0]);
+ err_code |= ERR_ALERT | ERR_FATAL;
+ goto out;
+ }
+ }
#endif
else if (!strcmp(args[0], "tune.bufsize")) {
if (*(args[1]) == 0) {
@@ -1241,6 +1254,8 @@
struct sockaddr_storage *sk;
int port1, port2;
struct logsrv *logsrv;
+ int arg = 0;
+ int len = 0;
if (*(args[1]) == 0 || *(args[2]) == 0) {
Alert("parsing [%s:%d] : '%s' expects <address> and <facility> as arguments.\n", file, linenum, args[0]);
@@ -1250,28 +1265,50 @@
logsrv = calloc(1, sizeof(struct logsrv));
- logsrv->facility = get_log_facility(args[2]);
+ /* just after the address, a length may be specified */
+ if (strcmp(args[arg+2], "len") == 0) {
+ len = atoi(args[arg+3]);
+ if (len < 80 || len > 65535) {
+ Alert("parsing [%s:%d] : invalid log length '%s', must be between 80 and 65535.\n",
+ file, linenum, args[arg+3]);
+ err_code |= ERR_ALERT | ERR_FATAL;
+ goto out;
+ }
+ logsrv->maxlen = len;
+
+ /* skip these two args */
+ arg += 2;
+ }
+ else
+ logsrv->maxlen = MAX_SYSLOG_LEN;
+
+ if (logsrv->maxlen > global.max_syslog_len) {
+ global.max_syslog_len = logsrv->maxlen;
+ logline = realloc(logline, global.max_syslog_len + 1);
+ }
+
+ logsrv->facility = get_log_facility(args[arg+2]);
if (logsrv->facility < 0) {
- Alert("parsing [%s:%d] : unknown log facility '%s'\n", file, linenum, args[2]);
+ Alert("parsing [%s:%d] : unknown log facility '%s'\n", file, linenum, args[arg+2]);
err_code |= ERR_ALERT | ERR_FATAL;
logsrv->facility = 0;
}
logsrv->level = 7; /* max syslog level = debug */
- if (*(args[3])) {
- logsrv->level = get_log_level(args[3]);
+ if (*(args[arg+3])) {
+ logsrv->level = get_log_level(args[arg+3]);
if (logsrv->level < 0) {
- Alert("parsing [%s:%d] : unknown optional log level '%s'\n", file, linenum, args[3]);
+ Alert("parsing [%s:%d] : unknown optional log level '%s'\n", file, linenum, args[arg+3]);
err_code |= ERR_ALERT | ERR_FATAL;
logsrv->level = 0;
}
}
logsrv->minlvl = 0; /* limit syslog level to this level (emerg) */
- if (*(args[4])) {
- logsrv->minlvl = get_log_level(args[4]);
+ if (*(args[arg+4])) {
+ logsrv->minlvl = get_log_level(args[arg+4]);
if (logsrv->minlvl < 0) {
- Alert("parsing [%s:%d] : unknown optional minimum log level '%s'\n", file, linenum, args[4]);
+ Alert("parsing [%s:%d] : unknown optional minimum log level '%s'\n", file, linenum, args[arg+4]);
err_code |= ERR_ALERT | ERR_FATAL;
logsrv->minlvl = 0;
}
@@ -1514,11 +1551,14 @@
const char *cmd, const char *reg, const char *repl,
const char **cond_start)
{
- regex_t *preg = NULL;
+ struct my_regex *preg = NULL;
char *errmsg = NULL;
const char *err;
+ char *error;
int ret_code = 0;
struct acl_cond *cond = NULL;
+ int cs;
+ int cap;
if (px == &defproxy) {
Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, line, cmd);
@@ -1557,15 +1597,19 @@
((px->cap & PR_CAP_BE) ? SMP_VAL_BE_HRS_HDR : SMP_VAL_FE_HRS_HDR),
file, line);
- preg = calloc(1, sizeof(regex_t));
+ preg = calloc(1, sizeof(*preg));
if (!preg) {
Alert("parsing [%s:%d] : '%s' : not enough memory to build regex.\n", file, line, cmd);
ret_code = ERR_ALERT | ERR_FATAL;
goto err;
}
- if (regcomp(preg, reg, REG_EXTENDED | flags) != 0) {
- Alert("parsing [%s:%d] : '%s' : bad regular expression '%s'.\n", file, line, cmd, reg);
+ cs = !(flags & REG_ICASE);
+ cap = !(flags & REG_NOSUB);
+ error = NULL;
+ if (!regex_comp(reg, preg, cs, cap, &error)) {
+ Alert("parsing [%s:%d] : '%s' : regular expression '%s' : %s\n", file, line, cmd, reg, error);
+ free(error);
ret_code = ERR_ALERT | ERR_FATAL;
goto err;
}
@@ -1585,7 +1629,7 @@
return ret_code;
err_free:
- regfree(preg);
+ regex_free(preg);
err:
free(preg);
free(errmsg);
@@ -1798,6 +1842,7 @@
{
static struct proxy *curproxy = NULL;
const char *err;
+ char *error;
int rc;
unsigned val;
int err_code = 0;
@@ -1958,8 +2003,8 @@
curproxy->expect_str = strdup(defproxy.expect_str);
if (defproxy.expect_regex) {
/* note: this regex is known to be valid */
- curproxy->expect_regex = calloc(1, sizeof(regex_t));
- regcomp(curproxy->expect_regex, defproxy.expect_str, REG_EXTENDED);
+ curproxy->expect_regex = calloc(1, sizeof(*curproxy->expect_regex));
+ regex_comp(defproxy.expect_str, curproxy->expect_regex, 1, 1, NULL);
}
}
@@ -2007,6 +2052,7 @@
if (curproxy->cap & PR_CAP_FE) {
curproxy->timeout.client = defproxy.timeout.client;
+ curproxy->timeout.clientfin = defproxy.timeout.clientfin;
curproxy->timeout.tarpit = defproxy.timeout.tarpit;
curproxy->timeout.httpreq = defproxy.timeout.httpreq;
curproxy->timeout.httpka = defproxy.timeout.httpka;
@@ -2035,6 +2081,7 @@
if (curproxy->cap & PR_CAP_BE) {
curproxy->timeout.connect = defproxy.timeout.connect;
curproxy->timeout.server = defproxy.timeout.server;
+ curproxy->timeout.serverfin = defproxy.timeout.serverfin;
curproxy->timeout.check = defproxy.timeout.check;
curproxy->timeout.queue = defproxy.timeout.queue;
curproxy->timeout.tarpit = defproxy.timeout.tarpit;
@@ -2103,7 +2150,11 @@
free(defproxy.server_id_hdr_name);
defproxy.server_id_hdr_len = 0;
free(defproxy.expect_str);
- if (defproxy.expect_regex) regfree(defproxy.expect_regex);
+ if (defproxy.expect_regex) {
+ regex_free(defproxy.expect_regex);
+ free(defproxy.expect_regex);
+ defproxy.expect_regex = NULL;
+ }
if (defproxy.conf.logformat_string != default_http_log_format &&
defproxy.conf.logformat_string != default_tcp_log_format &&
@@ -3869,7 +3920,7 @@
curproxy->options2 &= ~PR_O2_CHK_ANY;
curproxy->options2 |= PR_O2_MYSQL_CHK;
- /* This is an exemple of an MySQL >=4.0 client Authentication packet kindly provided by Cyril Bonte.
+ /* This is an example of a MySQL >=4.0 client Authentication packet kindly provided by Cyril Bonte.
* const char mysql40_client_auth_pkt[] = {
* "\x0e\x00\x00" // packet length
* "\x01" // packet number
@@ -3883,6 +3934,23 @@
* };
*/
+ /* This is an example of a MySQL >=4.1 client Authentication packet provided by Nenad Merdanovic.
+ * const char mysql41_client_auth_pkt[] = {
+ * "\x0e\x00\x00\" // packet length
+ * "\x01" // packet number
+ * "\x00\x00\x00\x00" // client capabilities
+ * "\x00\x00\x00\x01" // max packet
+ * "\x21" // character set (UTF-8)
+ * char[23] // All zeroes
+ * "haproxy\x00" // username (null terminated string)
+ * "\x00" // filler (always 0x00)
+ * "\x01\x00\x00" // packet length
+ * "\x00" // packet number
+ * "\x01" // COM_QUIT command
+ * };
+ */
+
+
if (*(args[2])) {
int cur_arg = 2;
@@ -3900,25 +3968,55 @@
}
mysqluser = args[cur_arg + 1];
userlen = strlen(mysqluser);
- packetlen = userlen + 7;
- reqlen = packetlen + 9;
- free(curproxy->check_req);
- curproxy->check_req = (char *)calloc(1, reqlen);
- curproxy->check_len = reqlen;
-
- snprintf(curproxy->check_req, 4, "%c%c%c",
- ((unsigned char) packetlen & 0xff),
- ((unsigned char) (packetlen >> 8) & 0xff),
- ((unsigned char) (packetlen >> 16) & 0xff));
-
- curproxy->check_req[3] = 1;
- curproxy->check_req[5] = 128;
- curproxy->check_req[8] = 1;
- memcpy(&curproxy->check_req[9], mysqluser, userlen);
- curproxy->check_req[9 + userlen + 1 + 1] = 1;
- curproxy->check_req[9 + userlen + 1 + 1 + 4] = 1;
- cur_arg += 2;
+ if (*(args[cur_arg+2])) {
+ if (!strcmp(args[cur_arg+2], "post-41")) {
+ packetlen = userlen + 7 + 27;
+ reqlen = packetlen + 9;
+
+ free(curproxy->check_req);
+ curproxy->check_req = (char *)calloc(1, reqlen);
+ curproxy->check_len = reqlen;
+
+ snprintf(curproxy->check_req, 4, "%c%c%c",
+ ((unsigned char) packetlen & 0xff),
+ ((unsigned char) (packetlen >> 8) & 0xff),
+ ((unsigned char) (packetlen >> 16) & 0xff));
+
+ curproxy->check_req[3] = 1;
+ curproxy->check_req[5] = 130;
+ curproxy->check_req[11] = 1;
+ curproxy->check_req[12] = 33;
+ memcpy(&curproxy->check_req[36], mysqluser, userlen);
+ curproxy->check_req[36 + userlen + 1 + 1] = 1;
+ curproxy->check_req[36 + userlen + 1 + 1 + 4] = 1;
+ cur_arg += 3;
+ } else {
+ Alert("parsing [%s:%d] : keyword '%s' only supports option 'post-41'.\n", file, linenum, args[cur_arg+2]);
+ err_code |= ERR_ALERT | ERR_FATAL;
+ goto out;
+ }
+ } else {
+ packetlen = userlen + 7;
+ reqlen = packetlen + 9;
+
+ free(curproxy->check_req);
+ curproxy->check_req = (char *)calloc(1, reqlen);
+ curproxy->check_len = reqlen;
+
+ snprintf(curproxy->check_req, 4, "%c%c%c",
+ ((unsigned char) packetlen & 0xff),
+ ((unsigned char) (packetlen >> 8) & 0xff),
+ ((unsigned char) (packetlen >> 16) & 0xff));
+
+ curproxy->check_req[3] = 1;
+ curproxy->check_req[5] = 128;
+ curproxy->check_req[8] = 1;
+ memcpy(&curproxy->check_req[9], mysqluser, userlen);
+ curproxy->check_req[9 + userlen + 1 + 1] = 1;
+ curproxy->check_req[9 + userlen + 1 + 1 + 4] = 1;
+ cur_arg += 2;
+ }
} else {
/* unknown suboption - catchall */
Alert("parsing [%s:%d] : '%s %s' only supports optional values: 'user'.\n",
@@ -4146,12 +4244,18 @@
}
curproxy->options2 |= PR_O2_EXP_RSTS;
free(curproxy->expect_str);
- if (curproxy->expect_regex) regfree(curproxy->expect_regex);
+ if (curproxy->expect_regex) {
+ regex_free(curproxy->expect_regex);
+ free(curproxy->expect_regex);
+ curproxy->expect_regex = NULL;
+ }
curproxy->expect_str = strdup(args[cur_arg + 1]);
- curproxy->expect_regex = calloc(1, sizeof(regex_t));
- if (regcomp(curproxy->expect_regex, args[cur_arg + 1], REG_EXTENDED) != 0) {
- Alert("parsing [%s:%d] : '%s %s %s' : bad regular expression '%s'.\n",
- file, linenum, args[0], args[1], ptr_arg, args[cur_arg + 1]);
+ curproxy->expect_regex = calloc(1, sizeof(*curproxy->expect_regex));
+ error = NULL;
+ if (!regex_comp(args[cur_arg + 1], curproxy->expect_regex, 1, 1, &error)) {
+ Alert("parsing [%s:%d] : '%s %s %s' : bad regular expression '%s': %s.\n",
+ file, linenum, args[0], args[1], ptr_arg, args[cur_arg + 1], error);
+ free(error);
err_code |= ERR_ALERT | ERR_FATAL;
goto out;
}
@@ -4165,12 +4269,18 @@
}
curproxy->options2 |= PR_O2_EXP_RSTR;
free(curproxy->expect_str);
- if (curproxy->expect_regex) regfree(curproxy->expect_regex);
+ if (curproxy->expect_regex) {
+ regex_free(curproxy->expect_regex);
+ free(curproxy->expect_regex);
+ curproxy->expect_regex = NULL;
+ }
curproxy->expect_str = strdup(args[cur_arg + 1]);
- curproxy->expect_regex = calloc(1, sizeof(regex_t));
- if (regcomp(curproxy->expect_regex, args[cur_arg + 1], REG_EXTENDED) != 0) {
- Alert("parsing [%s:%d] : '%s %s %s' : bad regular expression '%s'.\n",
- file, linenum, args[0], args[1], ptr_arg, args[cur_arg + 1]);
+ curproxy->expect_regex = calloc(1, sizeof(*curproxy->expect_regex));
+ error = NULL;
+ if (!regex_comp(args[cur_arg + 1], curproxy->expect_regex, 1, 1, &error)) {
+ Alert("parsing [%s:%d] : '%s %s %s' : bad regular expression '%s': %s.\n",
+ file, linenum, args[0], args[1], ptr_arg, args[cur_arg + 1], error);
+ free(error);
err_code |= ERR_ALERT | ERR_FATAL;
goto out;
}
@@ -4382,10 +4492,12 @@
tcpcheck->action = TCPCHK_ACT_EXPECT;
tcpcheck->string_len = 0;
tcpcheck->string = NULL;
- tcpcheck->expect_regex = calloc(1, sizeof(regex_t));
- if (regcomp(tcpcheck->expect_regex, args[cur_arg + 1], REG_EXTENDED) != 0) {
- Alert("parsing [%s:%d] : '%s %s %s' : bad regular expression '%s'.\n",
- file, linenum, args[0], args[1], ptr_arg, args[cur_arg + 1]);
+ tcpcheck->expect_regex = calloc(1, sizeof(*tcpcheck->expect_regex));
+ error = NULL;
+ if (!regex_comp(args[cur_arg + 1], tcpcheck->expect_regex, 1, 1, &error)) {
+ Alert("parsing [%s:%d] : '%s %s %s' : bad regular expression '%s': %s.\n",
+ file, linenum, args[0], args[1], ptr_arg, args[cur_arg + 1], error);
+ free(error);
err_code |= ERR_ALERT | ERR_FATAL;
goto out;
}
@@ -4703,22 +4815,46 @@
else if (*(args[1]) && *(args[2])) {
struct sockaddr_storage *sk;
int port1, port2;
+ int arg = 0;
+ int len = 0;
logsrv = calloc(1, sizeof(struct logsrv));
- logsrv->facility = get_log_facility(args[2]);
+ /* just after the address, a length may be specified */
+ if (strcmp(args[arg+2], "len") == 0) {
+ len = atoi(args[arg+3]);
+ if (len < 80 || len > 65535) {
+ Alert("parsing [%s:%d] : invalid log length '%s', must be between 80 and 65535.\n",
+ file, linenum, args[arg+3]);
+ err_code |= ERR_ALERT | ERR_FATAL;
+ goto out;
+ }
+ logsrv->maxlen = len;
+
+ /* skip these two args */
+ arg += 2;
+ }
+ else
+ logsrv->maxlen = MAX_SYSLOG_LEN;
+
+ if (logsrv->maxlen > global.max_syslog_len) {
+ global.max_syslog_len = logsrv->maxlen;
+ logline = realloc(logline, global.max_syslog_len + 1);
+ }
+
+ logsrv->facility = get_log_facility(args[arg+2]);
if (logsrv->facility < 0) {
- Alert("parsing [%s:%d] : unknown log facility '%s'\n", file, linenum, args[2]);
+ Alert("parsing [%s:%d] : unknown log facility '%s'\n", file, linenum, args[arg+2]);
err_code |= ERR_ALERT | ERR_FATAL;
goto out;
}
logsrv->level = 7; /* max syslog level = debug */
- if (*(args[3])) {
- logsrv->level = get_log_level(args[3]);
+ if (*(args[arg+3])) {
+ logsrv->level = get_log_level(args[arg+3]);
if (logsrv->level < 0) {
- Alert("parsing [%s:%d] : unknown optional log level '%s'\n", file, linenum, args[3]);
+ Alert("parsing [%s:%d] : unknown optional log level '%s'\n", file, linenum, args[arg+3]);
err_code |= ERR_ALERT | ERR_FATAL;
goto out;
@@ -4726,10 +4862,10 @@
}
logsrv->minlvl = 0; /* limit syslog level to this level (emerg) */
- if (*(args[4])) {
- logsrv->minlvl = get_log_level(args[4]);
+ if (*(args[arg+4])) {
+ logsrv->minlvl = get_log_level(args[arg+4]);
if (logsrv->minlvl < 0) {
- Alert("parsing [%s:%d] : unknown optional minimum log level '%s'\n", file, linenum, args[4]);
+ Alert("parsing [%s:%d] : unknown optional minimum log level '%s'\n", file, linenum, args[arg+4]);
err_code |= ERR_ALERT | ERR_FATAL;
goto out;
@@ -6442,6 +6578,13 @@
memcpy(curproxy->check_req, sslv3_client_hello_pkt, curproxy->check_len);
}
+ if (!LIST_ISEMPTY(&curproxy->tcpcheck_rules) &&
+ (curproxy->options2 & PR_O2_CHK_ANY) != PR_O2_TCPCHK_CHK) {
+ Warning("config : %s '%s' uses tcp-check rules without 'option tcp-check', so the rules are ignored.\n",
+ proxy_type_str(curproxy), curproxy->id);
+ err_code |= ERR_WARN;
+ }
+
/* ensure that cookie capture length is not too large */
if (curproxy->capture_len >= global.tune.cookie_len) {
Warning("config : truncating capture length to %d bytes for %s '%s'.\n",
@@ -6452,31 +6595,15 @@
/* The small pools required for the capture lists */
if (curproxy->nb_req_cap) {
- if (curproxy->mode == PR_MODE_HTTP) {
- curproxy->req_cap_pool = create_pool("ptrcap",
- curproxy->nb_req_cap * sizeof(char *),
- MEM_F_SHARED);
- } else {
- Warning("config : 'capture request header' ignored for %s '%s' as it requires HTTP mode.\n",
- proxy_type_str(curproxy), curproxy->id);
- err_code |= ERR_WARN;
- curproxy->to_log &= ~LW_REQHDR;
- curproxy->nb_req_cap = 0;
- }
+ curproxy->req_cap_pool = create_pool("ptrcap",
+ curproxy->nb_req_cap * sizeof(char *),
+ MEM_F_SHARED);
}
if (curproxy->nb_rsp_cap) {
- if (curproxy->mode == PR_MODE_HTTP) {
- curproxy->rsp_cap_pool = create_pool("ptrcap",
- curproxy->nb_rsp_cap * sizeof(char *),
- MEM_F_SHARED);
- } else {
- Warning("config : 'capture response header' ignored for %s '%s' as it requires HTTP mode.\n",
- proxy_type_str(curproxy), curproxy->id);
- err_code |= ERR_WARN;
- curproxy->to_log &= ~LW_REQHDR;
- curproxy->nb_rsp_cap = 0;
- }
+ curproxy->rsp_cap_pool = create_pool("ptrcap",
+ curproxy->nb_rsp_cap * sizeof(char *),
+ MEM_F_SHARED);
}
/* first, we will invert the servers list order */
|
[-]
[+]
|
Changed |
haproxy-1.5.3.tar.gz/src/checks.c
^
|
@@ -1351,6 +1351,104 @@
}
/*
+ * establish a server health-check.
+ *
+ * It can return one of :
+ * - SN_ERR_NONE if everything's OK and tcpcheck_main() was not called
+ * - SN_ERR_UP if if everything's OK and tcpcheck_main() was called
+ * - SN_ERR_SRVTO if there are no more servers
+ * - SN_ERR_SRVCL if the connection was refused by the server
+ * - SN_ERR_PRXCOND if the connection has been limited by the proxy (maxconn)
+ * - SN_ERR_RESOURCE if a system resource is lacking (eg: fd limits, ports, ...)
+ * - SN_ERR_INTERNAL for any other purely internal errors
+ * Additionnally, in the case of SN_ERR_RESOURCE, an emergency log will be emitted.
+ * Note that we try to prevent the network stack from sending the ACK during the
+ * connect() when a pure TCP check is used (without PROXY protocol).
+ */
+static int connect_chk(struct task *t)
+{
+ struct check *check = t->context;
+ struct server *s = check->server;
+ struct connection *conn = check->conn;
+ struct protocol *proto;
+ int ret;
+
+ /* tcpcheck send/expect initialisation */
+ if (check->type == PR_O2_TCPCHK_CHK)
+ check->current_step = NULL;
+
+ /* prepare the check buffer.
+ * This should not be used if check is the secondary agent check
+ * of a server as s->proxy->check_req will relate to the
+ * configuration of the primary check. Similarly, tcp-check uses
+ * its own strings.
+ */
+ if (check->type && check->type != PR_O2_TCPCHK_CHK && !(check->state & CHK_ST_AGENT)) {
+ bo_putblk(check->bo, s->proxy->check_req, s->proxy->check_len);
+
+ /* we want to check if this host replies to HTTP or SSLv3 requests
+ * so we'll send the request, and won't wake the checker up now.
+ */
+ if ((check->type) == PR_O2_SSL3_CHK) {
+ /* SSL requires that we put Unix time in the request */
+ int gmt_time = htonl(date.tv_sec);
+ memcpy(check->bo->data + 11, &gmt_time, 4);
+ }
+ else if ((check->type) == PR_O2_HTTP_CHK) {
+ if (s->proxy->options2 & PR_O2_CHK_SNDST)
+ bo_putblk(check->bo, trash.str, httpchk_build_status_header(s, trash.str, trash.size));
+ bo_putstr(check->bo, "\r\n");
+ *check->bo->p = '\0'; /* to make gdb output easier to read */
+ }
+ }
+
+ /* prepare a new connection */
+ conn_init(conn);
+ conn_prepare(conn, s->check_common.proto, s->check_common.xprt);
+ conn_attach(conn, check, &check_conn_cb);
+ conn->target = &s->obj_type;
+
+ /* no client address */
+ clear_addr(&conn->addr.from);
+
+ if (is_addr(&s->check_common.addr)) {
+
+ /* we'll connect to the check addr specified on the server */
+ conn->addr.to = s->check_common.addr;
+ proto = s->check_common.proto;
+ }
+ else {
+ /* we'll connect to the addr on the server */
+ conn->addr.to = s->addr;
+ proto = s->proto;
+ }
+
+ if (check->port) {
+ set_host_port(&conn->addr.to, check->port);
+ }
+
+ if (check->type == PR_O2_TCPCHK_CHK) {
+ struct tcpcheck_rule *r = (struct tcpcheck_rule *) s->proxy->tcpcheck_rules.n;
+ /* if first step is a 'connect', then tcpcheck_main must run it */
+ if (r->action == TCPCHK_ACT_CONNECT) {
+ tcpcheck_main(conn);
+ return SN_ERR_UP;
+ }
+ }
+
+ ret = SN_ERR_INTERNAL;
+ if (proto->connect)
+ ret = proto->connect(conn, check->type, (check->type) ? 0 : 2);
+ conn->flags |= CO_FL_WAKE_DATA;
+ if (s->check.send_proxy) {
+ conn->send_proxy_ofs = 1;
+ conn->flags |= CO_FL_SEND_PROXY;
+ }
+
+ return ret;
+}
+
+/*
* manages a server health-check. Returns
* the time the task accepts to wait, or TIME_ETERNITY for infinity.
*/
@@ -1359,7 +1457,6 @@
struct check *check = t->context;
struct server *s = check->server;
struct connection *conn = check->conn;
- struct protocol *proto;
int rv;
int ret;
int expired = tick_is_expired(t->expire, now_ms);
@@ -1386,90 +1483,10 @@
check->bo->p = check->bo->data;
check->bo->o = 0;
- /* tcpcheck send/expect initialisation */
- if (check->type == PR_O2_TCPCHK_CHK)
- check->current_step = NULL;
-
- /* prepare the check buffer.
- * This should not be used if check is the secondary agent check
- * of a server as s->proxy->check_req will relate to the
- * configuration of the primary check. Similarly, tcp-check uses
- * its own strings.
- */
- if (check->type && check->type != PR_O2_TCPCHK_CHK && !(check->state & CHK_ST_AGENT)) {
- bo_putblk(check->bo, s->proxy->check_req, s->proxy->check_len);
-
- /* we want to check if this host replies to HTTP or SSLv3 requests
- * so we'll send the request, and won't wake the checker up now.
- */
- if ((check->type) == PR_O2_SSL3_CHK) {
- /* SSL requires that we put Unix time in the request */
- int gmt_time = htonl(date.tv_sec);
- memcpy(check->bo->data + 11, &gmt_time, 4);
- }
- else if ((check->type) == PR_O2_HTTP_CHK) {
- if (s->proxy->options2 & PR_O2_CHK_SNDST)
- bo_putblk(check->bo, trash.str, httpchk_build_status_header(s, trash.str, trash.size));
- bo_putstr(check->bo, "\r\n");
- *check->bo->p = '\0'; /* to make gdb output easier to read */
- }
- }
-
- /* prepare a new connection */
- conn_init(conn);
- conn_prepare(conn, s->check_common.proto, s->check_common.xprt);
- conn_attach(conn, check, &check_conn_cb);
- conn->target = &s->obj_type;
-
- /* no client address */
- clear_addr(&conn->addr.from);
-
- if (is_addr(&s->check_common.addr)) {
- /* we'll connect to the check addr specified on the server */
- conn->addr.to = s->check_common.addr;
- proto = s->check_common.proto;
- }
- else {
- /* we'll connect to the addr on the server */
- conn->addr.to = s->addr;
- proto = s->proto;
- }
-
- if (check->port) {
- set_host_port(&conn->addr.to, check->port);
- }
-
- if (check->type == PR_O2_TCPCHK_CHK) {
- struct tcpcheck_rule *r = (struct tcpcheck_rule *) s->proxy->tcpcheck_rules.n;
- /* if first step is a 'connect', then tcpcheck_main must run it */
- if (r->action == TCPCHK_ACT_CONNECT) {
- tcpcheck_main(conn);
- return t;
- }
- }
-
-
- /* It can return one of :
- * - SN_ERR_NONE if everything's OK
- * - SN_ERR_SRVTO if there are no more servers
- * - SN_ERR_SRVCL if the connection was refused by the server
- * - SN_ERR_PRXCOND if the connection has been limited by the proxy (maxconn)
- * - SN_ERR_RESOURCE if a system resource is lacking (eg: fd limits, ports, ...)
- * - SN_ERR_INTERNAL for any other purely internal errors
- * Additionnally, in the case of SN_ERR_RESOURCE, an emergency log will be emitted.
- * Note that we try to prevent the network stack from sending the ACK during the
- * connect() when a pure TCP check is used (without PROXY protocol).
- */
- ret = SN_ERR_INTERNAL;
- if (proto->connect)
- ret = proto->connect(conn, check->type, (check->type) ? 0 : 2);
- conn->flags |= CO_FL_WAKE_DATA;
- if (s->check.send_proxy) {
- conn->send_proxy_ofs = 1;
- conn->flags |= CO_FL_SEND_PROXY;
- }
-
+ ret = connect_chk(t);
switch (ret) {
+ case SN_ERR_UP:
+ return t;
case SN_ERR_NONE:
/* we allow up to min(inter, timeout.connect) for a connection
* to establish but only when timeout.check is set
@@ -1524,7 +1541,7 @@
* First, let's check whether there was an uncaught error,
* which can happen on connect timeout or error.
*/
- if (s->check.result == CHK_RES_UNKNOWN) {
+ if (check->result == CHK_RES_UNKNOWN) {
/* good connection is enough for pure TCP check */
if ((conn->flags & CO_FL_CONNECTED) && !check->type) {
if (check->use_ssl)
@@ -1713,7 +1730,7 @@
if ((s->proxy->options2 & PR_O2_EXP_TYPE) == PR_O2_EXP_STS)
ret = strncmp(s->proxy->expect_str, status_code, 3) == 0;
else
- ret = regexec(s->proxy->expect_regex, status_code, MAX_MATCH, pmatch, 0) == 0;
+ ret = regex_exec(s->proxy->expect_regex, status_code);
/* we necessarily have the response, so there are no partial failures */
if (s->proxy->options2 & PR_O2_EXP_INV)
@@ -1765,7 +1782,7 @@
if ((s->proxy->options2 & PR_O2_EXP_TYPE) == PR_O2_EXP_STR)
ret = strstr(contentptr, s->proxy->expect_str) != NULL;
else
- ret = regexec(s->proxy->expect_regex, contentptr, MAX_MATCH, pmatch, 0) == 0;
+ ret = regex_exec(s->proxy->expect_regex, contentptr);
/* if we don't match, we may need to wait more */
if (!ret && !done)
@@ -2118,7 +2135,7 @@
if (cur->string != NULL)
ret = my_memmem(contentptr, check->bi->i, cur->string, cur->string_len) != NULL;
else if (cur->expect_regex != NULL)
- ret = regexec(cur->expect_regex, contentptr, MAX_MATCH, pmatch, 0) == 0;
+ ret = regex_exec(cur->expect_regex, contentptr);
if (!ret && !done)
continue; /* try to read more */
|
[-]
[+]
|
Changed |
haproxy-1.5.3.tar.gz/src/connection.c
^
|
@@ -243,6 +243,8 @@
int conn_recv_proxy(struct connection *conn, int flag)
{
char *line, *end;
+ struct proxy_hdr_v2 *hdr_v2;
+ const char v2sig[] = PP2_SIGNATURE;
/* we might have been called just after an asynchronous shutr */
if (conn->flags & CO_FL_SOCK_RD_SH)
@@ -280,13 +282,11 @@
end = trash.str + trash.len;
/* Decode a possible proxy request, fail early if it does not match */
- if (strncmp(line, "PROXY ", 6) != 0) {
- conn->err_code = CO_ER_PRX_NOT_HDR;
- goto fail;
- }
+ if (strncmp(line, "PROXY ", 6) != 0)
+ goto not_v1;
line += 6;
- if (trash.len < 18) /* shortest possible line */
+ if (trash.len < 9) /* shortest possible line */
goto missing;
if (!memcmp(line, "TCP4 ", 5) != 0) {
@@ -391,17 +391,74 @@
((struct sockaddr_in6 *)&conn->addr.to)->sin6_port = htons(dport);
conn->flags |= CO_FL_ADDR_FROM_SET | CO_FL_ADDR_TO_SET;
}
+ else if (memcmp(line, "UNKNOWN\r\n", 9) == 0) {
+ /* This can be a UNIX socket forwarded by an haproxy upstream */
+ line += 9;
+ }
else {
- /* The protocol does not match something known (TCP4/TCP6) */
+ /* The protocol does not match something known (TCP4/TCP6/UNKNOWN) */
conn->err_code = CO_ER_PRX_BAD_PROTO;
goto fail;
}
+ trash.len = line - trash.str;
+ goto eat_header;
+
+ not_v1:
+ /* try PPv2 */
+ if (trash.len < PP2_HEADER_LEN)
+ goto missing;
+
+ hdr_v2 = (struct proxy_hdr_v2 *)trash.str;
+
+ if (memcmp(hdr_v2->sig, v2sig, PP2_SIGNATURE_LEN) != 0 ||
+ (hdr_v2->ver_cmd & PP2_VERSION_MASK) != PP2_VERSION) {
+ conn->err_code = CO_ER_PRX_NOT_HDR;
+ goto fail;
+ }
+
+ if (trash.len < PP2_HEADER_LEN + ntohs(hdr_v2->len))
+ goto missing;
+
+ switch (hdr_v2->ver_cmd & PP2_CMD_MASK) {
+ case 0x01: /* PROXY command */
+ switch (hdr_v2->fam) {
+ case 0x11: /* TCPv4 */
+ ((struct sockaddr_in *)&conn->addr.from)->sin_family = AF_INET;
+ ((struct sockaddr_in *)&conn->addr.from)->sin_addr.s_addr = hdr_v2->addr.ip4.src_addr;
+ ((struct sockaddr_in *)&conn->addr.from)->sin_port = hdr_v2->addr.ip4.src_port;
+ ((struct sockaddr_in *)&conn->addr.to)->sin_family = AF_INET;
+ ((struct sockaddr_in *)&conn->addr.to)->sin_addr.s_addr = hdr_v2->addr.ip4.dst_addr;
+ ((struct sockaddr_in *)&conn->addr.to)->sin_port = hdr_v2->addr.ip4.dst_port;
+ conn->flags |= CO_FL_ADDR_FROM_SET | CO_FL_ADDR_TO_SET;
+ break;
+ case 0x21: /* TCPv6 */
+ ((struct sockaddr_in6 *)&conn->addr.from)->sin6_family = AF_INET6;
+ memcpy(&((struct sockaddr_in6 *)&conn->addr.from)->sin6_addr, hdr_v2->addr.ip6.src_addr, 16);
+ ((struct sockaddr_in6 *)&conn->addr.from)->sin6_port = hdr_v2->addr.ip6.src_port;
+ ((struct sockaddr_in6 *)&conn->addr.to)->sin6_family = AF_INET6;
+ memcpy(&((struct sockaddr_in6 *)&conn->addr.to)->sin6_addr, hdr_v2->addr.ip6.dst_addr, 16);
+ ((struct sockaddr_in6 *)&conn->addr.to)->sin6_port = hdr_v2->addr.ip6.dst_port;
+ conn->flags |= CO_FL_ADDR_FROM_SET | CO_FL_ADDR_TO_SET;
+ break;
+ }
+ /* unsupported protocol, keep local connection address */
+ break;
+ case 0x00: /* LOCAL command */
+ /* keep local connection address for LOCAL */
+ break;
+ default:
+ goto bad_header; /* not a supported command */
+ }
+
+ trash.len = PP2_HEADER_LEN + ntohs(hdr_v2->len);
+ goto eat_header;
+
+ eat_header:
/* remove the PROXY line from the request. For this we re-read the
* exact line at once. If we don't get the exact same result, we
* fail.
*/
- trash.len = line - trash.str;
do {
int len2 = recv(conn->t.sock.fd, trash.str, trash.len, 0);
if (len2 < 0 && errno == EINTR)
@@ -554,10 +611,9 @@
int make_proxy_line_v2(char *buf, int buf_len, struct server *srv, struct connection *remote)
{
- const char pp2_signature[12] = {0x0D, 0x0A, 0x0D, 0x0A, 0x00, 0x0D, 0x0A, 0x51, 0x55, 0x49, 0x54, 0x0A};
+ const char pp2_signature[] = PP2_SIGNATURE;
int ret = 0;
- struct proxy_hdr_v2 *hdr_p = (struct proxy_hdr_v2 *)buf;
- union proxy_addr *addr_p = (union proxy_addr *)(buf + PP2_HEADER_LEN);
+ struct proxy_hdr_v2 *hdr = (struct proxy_hdr_v2 *)buf;
struct sockaddr_storage null_addr = {0};
struct sockaddr_storage *src = &null_addr;
struct sockaddr_storage *dst = &null_addr;
@@ -566,11 +622,12 @@
char *value = NULL;
struct tlv_ssl *tlv;
int ssl_tlv_len = 0;
+ struct chunk *cn_trash;
#endif
if (buf_len < PP2_HEADER_LEN)
return 0;
- memcpy(hdr_p->sig, pp2_signature, PP2_SIGNATURE_LEN);
+ memcpy(hdr->sig, pp2_signature, PP2_SIGNATURE_LEN);
if (remote) {
src = &remote->addr.from;
@@ -579,30 +636,30 @@
if (src && dst && src->ss_family == dst->ss_family && src->ss_family == AF_INET) {
if (buf_len < PP2_HDR_LEN_INET)
return 0;
- hdr_p->cmd = PP2_VERSION | PP2_CMD_PROXY;
- hdr_p->fam = PP2_FAM_INET | PP2_TRANS_STREAM;
- addr_p->ipv4_addr.src_addr = ((struct sockaddr_in *)src)->sin_addr.s_addr;
- addr_p->ipv4_addr.dst_addr = ((struct sockaddr_in *)dst)->sin_addr.s_addr;
- addr_p->ipv4_addr.src_port = ((struct sockaddr_in *)src)->sin_port;
- addr_p->ipv4_addr.dst_port = ((struct sockaddr_in *)dst)->sin_port;
+ hdr->ver_cmd = PP2_VERSION | PP2_CMD_PROXY;
+ hdr->fam = PP2_FAM_INET | PP2_TRANS_STREAM;
+ hdr->addr.ip4.src_addr = ((struct sockaddr_in *)src)->sin_addr.s_addr;
+ hdr->addr.ip4.dst_addr = ((struct sockaddr_in *)dst)->sin_addr.s_addr;
+ hdr->addr.ip4.src_port = ((struct sockaddr_in *)src)->sin_port;
+ hdr->addr.ip4.dst_port = ((struct sockaddr_in *)dst)->sin_port;
ret = PP2_HDR_LEN_INET;
}
else if (src && dst && src->ss_family == dst->ss_family && src->ss_family == AF_INET6) {
if (buf_len < PP2_HDR_LEN_INET6)
return 0;
- hdr_p->cmd = PP2_VERSION | PP2_CMD_PROXY;
- hdr_p->fam = PP2_FAM_INET6 | PP2_TRANS_STREAM;
- memcpy(addr_p->ipv6_addr.src_addr, &((struct sockaddr_in6 *)src)->sin6_addr, 16);
- memcpy(addr_p->ipv6_addr.dst_addr, &((struct sockaddr_in6 *)dst)->sin6_addr, 16);
- addr_p->ipv6_addr.src_port = ((struct sockaddr_in6 *)src)->sin6_port;
- addr_p->ipv6_addr.dst_port = ((struct sockaddr_in6 *)dst)->sin6_port;
+ hdr->ver_cmd = PP2_VERSION | PP2_CMD_PROXY;
+ hdr->fam = PP2_FAM_INET6 | PP2_TRANS_STREAM;
+ memcpy(hdr->addr.ip6.src_addr, &((struct sockaddr_in6 *)src)->sin6_addr, 16);
+ memcpy(hdr->addr.ip6.dst_addr, &((struct sockaddr_in6 *)dst)->sin6_addr, 16);
+ hdr->addr.ip6.src_port = ((struct sockaddr_in6 *)src)->sin6_port;
+ hdr->addr.ip6.dst_port = ((struct sockaddr_in6 *)dst)->sin6_port;
ret = PP2_HDR_LEN_INET6;
}
else {
if (buf_len < PP2_HDR_LEN_UNSPEC)
return 0;
- hdr_p->cmd = PP2_VERSION | PP2_CMD_LOCAL;
- hdr_p->fam = PP2_FAM_UNSPEC | PP2_TRANS_UNSPEC;
+ hdr->ver_cmd = PP2_VERSION | PP2_CMD_LOCAL;
+ hdr->fam = PP2_FAM_UNSPEC | PP2_TRANS_UNSPEC;
ret = PP2_HDR_LEN_UNSPEC;
}
@@ -626,9 +683,9 @@
tlv->verify = htonl(ssl_sock_get_verify_result(remote));
}
if (srv->pp_opts & SRV_PP_V2_SSL_CN) {
- value = ssl_sock_get_common_name(remote);
- if (value) {
- tlv_len = make_tlv(&buf[ret+ssl_tlv_len], (buf_len - ret - ssl_tlv_len), PP2_TYPE_SSL_CN, strlen(value), value);
+ cn_trash = get_trash_chunk();
+ if (ssl_sock_get_remote_common_name(remote, cn_trash) > 0) {
+ tlv_len = make_tlv(&buf[ret+ssl_tlv_len], (buf_len - ret - ssl_tlv_len), PP2_TYPE_SSL_CN, cn_trash->len, cn_trash->str);
ssl_tlv_len += tlv_len;
}
}
@@ -639,7 +696,7 @@
}
#endif
- hdr_p->len = htons((uint16_t)(ret - PP2_HEADER_LEN));
+ hdr->len = htons((uint16_t)(ret - PP2_HEADER_LEN));
return ret;
}
|
[-]
[+]
|
Changed |
haproxy-1.5.3.tar.gz/src/dumpstats.c
^
|
@@ -35,6 +35,7 @@
#include <common/time.h>
#include <common/uri_auth.h>
#include <common/version.h>
+#include <common/base64.h>
#include <types/global.h>
@@ -195,6 +196,7 @@
" add map : add map entry\n"
" del map : delete map entry\n"
" clear map <id> : clear the content of this map\n"
+ " set ssl <stmt> : set statement for ssl\n"
"";
static const char stats_permission_denied_msg[] =
@@ -489,7 +491,7 @@
"hrsp_1xx,hrsp_2xx,hrsp_3xx,hrsp_4xx,hrsp_5xx,hrsp_other,hanafail,"
"req_rate,req_rate_max,req_tot,"
"cli_abrt,srv_abrt,"
- "comp_in,comp_out,comp_byp,comp_rsp,lastsess,"
+ "comp_in,comp_out,comp_byp,comp_rsp,lastsess,last_chk,last_agt,qtime,ctime,rtime,ttime,"
"\n");
}
@@ -1789,6 +1791,50 @@
appctx->st0 = STAT_CLI_PRINT;
return 1;
}
+#ifdef USE_OPENSSL
+ else if (strcmp(args[1], "ssl") == 0) {
+ if (strcmp(args[2], "ocsp-response") == 0) {
+#ifdef SSL_CTRL_SET_TLSEXT_STATUS_REQ_CB
+ char *err = NULL;
+
+ /* Expect one parameter: the new response in base64 encoding */
+ if (!*args[3]) {
+ appctx->ctx.cli.msg = "'set ssl ocsp-response' expects response in base64 encoding.\n";
+ appctx->st0 = STAT_CLI_PRINT;
+ return 1;
+ }
+
+ trash.len = base64dec(args[3], strlen(args[3]), trash.str, trash.size);
+ if (trash.len < 0) {
+ appctx->ctx.cli.msg = "'set ssl ocsp-response' received invalid base64 encoded response.\n";
+ appctx->st0 = STAT_CLI_PRINT;
+ return 1;
+ }
+
+ if (ssl_sock_update_ocsp_response(&trash, &err)) {
+ if (err) {
+ memprintf(&err, "%s.\n", err);
+ appctx->ctx.cli.err = err;
+ appctx->st0 = STAT_CLI_PRINT_FREE;
+ }
+ return 1;
+ }
+ appctx->ctx.cli.msg = "OCSP Response updated!";
+ appctx->st0 = STAT_CLI_PRINT;
+ return 1;
+#else
+ appctx->ctx.cli.msg = "HAProxy was compiled against a version of OpenSSL that doesn't support OCSP stapling.\n";
+ appctx->st0 = STAT_CLI_PRINT;
+ return 1;
+#endif
+ }
+ else {
+ appctx->ctx.cli.msg = "'set ssl' only supports 'ocsp-response'.\n";
+ appctx->st0 = STAT_CLI_PRINT;
+ return 1;
+ }
+ }
+#endif
else { /* unknown "set" parameter */
return 0;
}
@@ -2743,8 +2789,8 @@
chunk_appendf(&trash, "%lld,",
px->fe_counters.p.http.comp_rsp);
- /* lastsess */
- chunk_appendf(&trash, ",");
+ /* lastsess, last_chk, last_agt, qtime, ctime, rtime, ttime, */
+ chunk_appendf(&trash, ",,,,,,,");
/* finish with EOL */
chunk_appendf(&trash, "\n");
@@ -2867,8 +2913,8 @@
",,"
/* compression: in, out, bypassed, comp_rsp */
",,,,"
- /* lastsess */
- ","
+ /* lastsess, last_chk, last_agt, qtime, ctime, rtime, ttime, */
+ ",,,,,,,"
"\n",
px->id, l->name,
l->nbconn, l->counters->conn_max,
@@ -3020,6 +3066,13 @@
U2H(sv->counters.p.http.rsp[0]), tot ? (int)(100*sv->counters.p.http.rsp[0] / tot) : 0);
}
+ chunk_appendf(&trash, "<tr><th colspan=3>Avg over last 1024 success. conn.</th></tr>");
+ chunk_appendf(&trash, "<tr><th>- Queue time:</th><td>%s</td><td>ms</td></tr>", U2H(swrate_avg(sv->counters.q_time, TIME_STATS_SAMPLES)));
+ chunk_appendf(&trash, "<tr><th>- Connect time:</th><td>%s</td><td>ms</td></tr>", U2H(swrate_avg(sv->counters.c_time, TIME_STATS_SAMPLES)));
+ if (px->mode == PR_MODE_HTTP)
+ chunk_appendf(&trash, "<tr><th>- Response time:</th><td>%s</td><td>ms</td></tr>", U2H(swrate_avg(sv->counters.d_time, TIME_STATS_SAMPLES)));
+ chunk_appendf(&trash, "<tr><th>- Total time:</th><td>%s</td><td>ms</td></tr>", U2H(swrate_avg(sv->counters.t_time, TIME_STATS_SAMPLES)));
+
chunk_appendf(&trash,
"</table></div></u></td>"
/* sessions: lbtot, last */
@@ -3056,7 +3109,8 @@
}
else if ((ref->agent.state & CHK_ST_ENABLED) && (ref->state == SRV_ST_STOPPED)) {
chunk_appendf(&trash, "%s ", human_time(now.tv_sec - ref->last_change, 1));
- chunk_appendf(&trash, srv_hlt_st[1]); /* DOWN (agent) */
+ /* DOWN (agent) */
+ chunk_appendf(&trash, srv_hlt_st[1], "GCC: your -Werror=format-security is bogus, annoying, and hides real bugs, I don't thank you, really!");
}
else if (ref->check.state & CHK_ST_ENABLED) {
chunk_appendf(&trash, "%s ", human_time(now.tv_sec - ref->last_change, 1));
@@ -3292,6 +3346,17 @@
/* lastsess */
chunk_appendf(&trash, "%d,", srv_lastsession(sv));
+ /* capture of last check and agent statuses */
+ chunk_appendf(&trash, "%s,", ((sv->check.state & (CHK_ST_ENABLED|CHK_ST_PAUSED)) == CHK_ST_ENABLED) ? cstr(sv->check.desc) : "");
+ chunk_appendf(&trash, "%s,", ((sv->agent.state & (CHK_ST_ENABLED|CHK_ST_PAUSED)) == CHK_ST_ENABLED) ? cstr(sv->agent.desc) : "");
+
+ /* qtime, ctime, rtime, ttime, */
+ chunk_appendf(&trash, "%u,%u,%u,%u,",
+ swrate_avg(sv->counters.q_time, TIME_STATS_SAMPLES),
+ swrate_avg(sv->counters.c_time, TIME_STATS_SAMPLES),
+ swrate_avg(sv->counters.d_time, TIME_STATS_SAMPLES),
+ swrate_avg(sv->counters.t_time, TIME_STATS_SAMPLES));
+
/* finish with EOL */
chunk_appendf(&trash, "\n");
}
@@ -3377,6 +3442,7 @@
"<tr><th>- HTTP 5xx responses:</th><td>%s</td></tr>"
"<tr><th>- other responses:</th><td>%s</td></tr>"
"<tr><th>Intercepted requests:</th><td>%s</td></tr>"
+ "<tr><th colspan=3>Avg over last 1024 success. conn.</th></tr>"
"",
U2H(px->be_counters.p.http.cum_req),
U2H(px->be_counters.p.http.rsp[1]),
@@ -3391,6 +3457,12 @@
U2H(px->be_counters.intercepted_req));
}
+ chunk_appendf(&trash, "<tr><th>- Queue time:</th><td>%s</td><td>ms</td></tr>", U2H(swrate_avg(px->be_counters.q_time, TIME_STATS_SAMPLES)));
+ chunk_appendf(&trash, "<tr><th>- Connect time:</th><td>%s</td><td>ms</td></tr>", U2H(swrate_avg(px->be_counters.c_time, TIME_STATS_SAMPLES)));
+ if (px->mode == PR_MODE_HTTP)
+ chunk_appendf(&trash, "<tr><th>- Response time:</th><td>%s</td><td>ms</td></tr>", U2H(swrate_avg(px->be_counters.d_time, TIME_STATS_SAMPLES)));
+ chunk_appendf(&trash, "<tr><th>- Total time:</th><td>%s</td><td>ms</td></tr>", U2H(swrate_avg(px->be_counters.t_time, TIME_STATS_SAMPLES)));
+
chunk_appendf(&trash,
"</table></div></u></td>"
/* sessions: lbtot, last */
@@ -3522,8 +3594,15 @@
/* compression: comp_rsp */
chunk_appendf(&trash, "%lld,", px->be_counters.p.http.comp_rsp);
- /* lastsess */
- chunk_appendf(&trash, "%d,", be_lastsession(px));
+ /* lastsess, last_chk, last_agt, */
+ chunk_appendf(&trash, "%d,,,", be_lastsession(px));
+
+ /* qtime, ctime, rtime, ttime, */
+ chunk_appendf(&trash, "%u,%u,%u,%u,",
+ swrate_avg(px->be_counters.q_time, TIME_STATS_SAMPLES),
+ swrate_avg(px->be_counters.c_time, TIME_STATS_SAMPLES),
+ swrate_avg(px->be_counters.d_time, TIME_STATS_SAMPLES),
+ swrate_avg(px->be_counters.t_time, TIME_STATS_SAMPLES));
/* finish with EOL */
chunk_appendf(&trash, "\n");
@@ -3631,7 +3710,7 @@
"<option value=\"\"></option>"
"<option value=\"ready\">Set state to READY</option>"
"<option value=\"drain\">Set state to DRAIN</option>"
- "<option value=\"maint\">set state to MAINT</option>"
+ "<option value=\"maint\">Set state to MAINT</option>"
"<option value=\"dhlth\">Health: disable checks</option>"
"<option value=\"ehlth\">Health: enable checks</option>"
"<option value=\"hrunn\">Health: force UP</option>"
|
[-]
[+]
|
Changed |
haproxy-1.5.3.tar.gz/src/frontend.c
^
|
@@ -106,16 +106,11 @@
if (global.tune.client_rcvbuf)
setsockopt(cfd, SOL_SOCKET, SO_RCVBUF, &global.tune.client_rcvbuf, sizeof(global.tune.client_rcvbuf));
- if (s->fe->mode == PR_MODE_HTTP) {
- /* the captures are only used in HTTP frontends */
- if (unlikely(s->fe->nb_req_cap > 0 &&
- (s->txn.req.cap = pool_alloc2(s->fe->req_cap_pool)) == NULL))
- goto out_return; /* no memory */
+ if (unlikely(s->fe->nb_req_cap > 0 && (s->txn.req.cap = pool_alloc2(s->fe->req_cap_pool)) == NULL))
+ goto out_return; /* no memory */
- if (unlikely(s->fe->nb_rsp_cap > 0 &&
- (s->txn.rsp.cap = pool_alloc2(s->fe->rsp_cap_pool)) == NULL))
- goto out_free_reqcap; /* no memory */
- }
+ if (unlikely(s->fe->nb_rsp_cap > 0 && (s->txn.rsp.cap = pool_alloc2(s->fe->rsp_cap_pool)) == NULL))
+ goto out_free_reqcap; /* no memory */
if (s->fe->http_needed) {
/* we have to allocate header indexes only if we know
|
[-]
[+]
|
Changed |
haproxy-1.5.3.tar.gz/src/haproxy.c
^
|
@@ -143,6 +143,7 @@
.chksize = BUFSIZE,
#ifdef USE_OPENSSL
.sslcachesize = SSLCACHESIZE,
+ .ssl_default_dh_param = SSL_DEFAULT_DH_PARAM,
#ifdef DEFAULT_SSL_MAX_RECORD
.ssl_max_record = DEFAULT_SSL_MAX_RECORD,
#endif
@@ -1033,8 +1034,8 @@
for (exp = p->req_exp; exp != NULL; ) {
if (exp->preg) {
- regfree((regex_t *)exp->preg);
- free((regex_t *)exp->preg);
+ regex_free(exp->preg);
+ free(exp->preg);
}
if (exp->replace && exp->action != ACT_SETBE)
@@ -1046,8 +1047,8 @@
for (exp = p->rsp_exp; exp != NULL; ) {
if (exp->preg) {
- regfree((regex_t *)exp->preg);
- free((regex_t *)exp->preg);
+ regex_free(exp->preg);
+ free(exp->preg);
}
if (exp->replace && exp->action != ACT_SETBE)
@@ -1202,6 +1203,7 @@
free(p->fwdfor_hdr_name);
free_http_req_rules(&p->http_req_rules);
+ free_http_res_rules(&p->http_res_rules);
free(p->task);
pool_destroy2(p->req_cap_pool);
@@ -1604,6 +1606,7 @@
if (proc == global.nbproc) {
if (global.mode & MODE_SYSTEMD) {
+ protocol_unbind_all();
for (proc = 0; proc < global.nbproc; proc++)
while (waitpid(children[proc], NULL, 0) == -1 && errno == EINTR);
}
|
[-]
[+]
|
Changed |
haproxy-1.5.3.tar.gz/src/hash.c
^
|
@@ -17,7 +17,7 @@
#include <common/hash.h>
-unsigned long hash_wt6(const char *key, int len)
+unsigned int hash_wt6(const char *key, int len)
{
unsigned h0 = 0xa53c965aUL;
unsigned h1 = 0x5ca6953aUL;
@@ -44,9 +44,9 @@
return h0 ^ h1;
}
-unsigned long hash_djb2(const char *key, int len)
+unsigned int hash_djb2(const char *key, int len)
{
- unsigned long hash = 5381;
+ unsigned int hash = 5381;
/* the hash unrolled eight times */
for (; len >= 8; len -= 8) {
@@ -72,9 +72,9 @@
return hash;
}
-unsigned long hash_sdbm(const char *key, int len)
+unsigned int hash_sdbm(const char *key, int len)
{
- unsigned long hash = 0;
+ unsigned int hash = 0;
int c;
while (len--) {
|
[-]
[+]
|
Changed |
haproxy-1.5.3.tar.gz/src/listener.c
^
|
@@ -95,15 +95,16 @@
if (l->state <= LI_PAUSED)
return 1;
- if (l->proto->sock_prot == IPPROTO_TCP) {
- if (shutdown(l->fd, SHUT_WR) != 0)
- return 0; /* Solaris dies here */
-
- if (listen(l->fd, l->backlog ? l->backlog : l->maxconn) != 0)
- return 0; /* OpenBSD dies here */
+ if (l->proto->pause) {
+ /* Returns < 0 in case of failure, 0 if the listener
+ * was totally stopped, or > 0 if correctly paused.
+ */
+ int ret = l->proto->pause(l);
- if (shutdown(l->fd, SHUT_RD) != 0)
- return 0; /* should always be OK */
+ if (ret < 0)
+ return 0;
+ else if (ret == 0)
+ return 1;
}
if (l->state == LI_LIMITED)
@@ -119,10 +120,26 @@
* may replace enable_listener(). The resulting state will either be LI_READY
* or LI_FULL. 0 is returned in case of failure to resume (eg: dead socket).
* Listeners bound to a different process are not woken up unless we're in
- * foreground mode.
+ * foreground mode. If the listener was only in the assigned state, it's totally
+ * rebound. This can happen if a pause() has completely stopped it. If the
+ * resume fails, 0 is returned and an error might be displayed.
*/
int resume_listener(struct listener *l)
{
+ if (l->state == LI_ASSIGNED) {
+ char msg[100];
+ int err;
+
+ err = l->proto->bind(l, msg, sizeof(msg));
+ if (err & ERR_ALERT)
+ Alert("Resuming listener: %s\n", msg);
+ else if (err & ERR_WARN)
+ Warning("Resuming listener: %s\n", msg);
+
+ if (err & (ERR_FATAL | ERR_ABORT))
+ return 0;
+ }
+
if (l->state < LI_PAUSED)
return 0;
@@ -236,6 +253,7 @@
if (listener->state >= LI_PAUSED) {
fd_delete(listener->fd);
+ listener->fd = -1;
listener->state = LI_ASSIGNED;
}
return ERR_NONE;
|
[-]
[+]
|
Changed |
haproxy-1.5.3.tar.gz/src/log.c
^
|
@@ -80,7 +80,7 @@
{ "CS", LOG_FMT_CSERVER, PR_MODE_HTTP, LW_RSPHDR, NULL }, /* server cookie */
{ "H", LOG_FMT_HOSTNAME, PR_MODE_TCP, LW_INIT, NULL }, /* Hostname */
{ "ID", LOG_FMT_UNIQUEID, PR_MODE_HTTP, LW_BYTES, NULL }, /* Unique ID */
- { "ST", LOG_FMT_STATUS, PR_MODE_HTTP, LW_RESP, NULL }, /* status code */
+ { "ST", LOG_FMT_STATUS, PR_MODE_TCP, LW_RESP, NULL }, /* status code */
{ "T", LOG_FMT_DATEGMT, PR_MODE_TCP, LW_INIT, NULL }, /* date GMT */
{ "Tc", LOG_FMT_TC, PR_MODE_TCP, LW_BYTES, NULL }, /* Tc */
{ "Tl", LOG_FMT_DATELOCAL, PR_MODE_TCP, LW_INIT, NULL }, /* date local timezone */
@@ -103,10 +103,10 @@
{ "fi", LOG_FMT_FRONTENDIP, PR_MODE_TCP, LW_FRTIP, NULL }, /* frontend ip */
{ "fp", LOG_FMT_FRONTENDPORT, PR_MODE_TCP, LW_FRTIP, NULL }, /* frontend port */
{ "ft", LOG_FMT_FRONTEND_XPRT, PR_MODE_TCP, LW_INIT, NULL }, /* frontend with transport mode */
- { "hr", LOG_FMT_HDRREQUEST, PR_MODE_HTTP, LW_REQHDR, NULL }, /* header request */
- { "hrl", LOG_FMT_HDRREQUESTLIST, PR_MODE_HTTP, LW_REQHDR, NULL }, /* header request list */
- { "hs", LOG_FMT_HDRRESPONS, PR_MODE_HTTP, LW_RSPHDR, NULL }, /* header response */
- { "hsl", LOG_FMT_HDRRESPONSLIST, PR_MODE_HTTP, LW_RSPHDR, NULL }, /* header response list */
+ { "hr", LOG_FMT_HDRREQUEST, PR_MODE_TCP, LW_REQHDR, NULL }, /* header request */
+ { "hrl", LOG_FMT_HDRREQUESTLIST, PR_MODE_TCP, LW_REQHDR, NULL }, /* header request list */
+ { "hs", LOG_FMT_HDRRESPONS, PR_MODE_TCP, LW_RSPHDR, NULL }, /* header response */
+ { "hsl", LOG_FMT_HDRRESPONSLIST, PR_MODE_TCP, LW_RSPHDR, NULL }, /* header response list */
{ "ms", LOG_FMT_MS, PR_MODE_TCP, LW_INIT, NULL }, /* accept date millisecond */
{ "pid", LOG_FMT_PID, PR_MODE_TCP, LW_INIT, NULL }, /* log pid */
{ "r", LOG_FMT_REQ, PR_MODE_HTTP, LW_REQ, NULL }, /* request */
@@ -146,7 +146,7 @@
/* This is a global syslog line, common to all outgoing messages. It begins
* with the syslog tag and the date that are updated by update_log_hdr().
*/
-static char logline[MAX_SYSLOG_LEN];
+char *logline = NULL;
struct logformat_var_args {
char *name;
@@ -736,7 +736,7 @@
tvsec = date.tv_sec;
get_localtime(tvsec, &tm);
- hdr_len = snprintf(logline, MAX_SYSLOG_LEN,
+ hdr_len = snprintf(logline, global.max_syslog_len,
"<<<<>%s %2d %02d:%02d:%02d %s%s[%d]: ",
monthname[tm.tm_mon],
tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec,
@@ -746,8 +746,8 @@
* either -1 or the number of bytes that would be needed to store
* the total message. In both cases, we must adjust it.
*/
- if (hdr_len < 0 || hdr_len > MAX_SYSLOG_LEN)
- hdr_len = MAX_SYSLOG_LEN;
+ if (hdr_len < 0 || hdr_len > global.max_syslog_len)
+ hdr_len = global.max_syslog_len;
dataptr = logline + hdr_len;
}
@@ -772,9 +772,9 @@
data_len = dataptr - logline;
va_start(argp, format);
- data_len += vsnprintf(dataptr, logline + sizeof(logline) - dataptr, format, argp);
- if (data_len < 0 || data_len > MAX_SYSLOG_LEN)
- data_len = MAX_SYSLOG_LEN;
+ data_len += vsnprintf(dataptr, logline + global.max_syslog_len - dataptr, format, argp);
+ if (data_len < 0 || data_len > global.max_syslog_len)
+ data_len = global.max_syslog_len;
va_end(argp);
__send_log(p, level, logline, data_len);
@@ -811,39 +811,6 @@
if (!logsrvs)
return;
- message[size - 1] = '\n';
-
- /* Lazily set up syslog sockets for protocol families of configured
- * syslog servers. */
- nblogger = 0;
- list_for_each_entry(tmp, logsrvs, list) {
- const struct logsrv *logsrv = tmp;
- int proto, *plogfd;
-
- if (logsrv->addr.ss_family == AF_UNIX) {
- proto = 0;
- plogfd = &logfdunix;
- } else {
- proto = IPPROTO_UDP;
- plogfd = &logfdinet;
- }
- if (*plogfd >= 0) {
- /* socket already created. */
- continue;
- }
- if ((*plogfd = socket(logsrv->addr.ss_family, SOCK_DGRAM,
- proto)) < 0) {
- Alert("socket for logger #%d failed: %s (errno=%d)\n",
- nblogger + 1, strerror(errno), errno);
- return;
- }
- /* we don't want to receive anything on this socket */
- setsockopt(*plogfd, SOL_SOCKET, SO_RCVBUF, &zero, sizeof(zero));
- /* does nothing under Linux, maybe needed for others */
- shutdown(*plogfd, SHUT_RD);
- nblogger++;
- }
-
/* Send log messages to syslog server. */
nblogger = 0;
list_for_each_entry(tmp, logsrvs, list) {
@@ -851,11 +818,30 @@
int *plogfd = logsrv->addr.ss_family == AF_UNIX ?
&logfdunix : &logfdinet;
int sent;
+ int max;
+ char backup;
+
+ nblogger++;
/* we can filter the level of the messages that are sent to each logger */
if (level > logsrv->level)
continue;
+ if (unlikely(*plogfd < 0)) {
+ /* socket not successfully initialized yet */
+ int proto = logsrv->addr.ss_family == AF_UNIX ? 0 : IPPROTO_UDP;
+
+ if ((*plogfd = socket(logsrv->addr.ss_family, SOCK_DGRAM, proto)) < 0) {
+ Alert("socket for logger #%d failed: %s (errno=%d)\n",
+ nblogger, strerror(errno), errno);
+ continue;
+ }
+ /* we don't want to receive anything on this socket */
+ setsockopt(*plogfd, SOL_SOCKET, SO_RCVBUF, &zero, sizeof(zero));
+ /* does nothing under Linux, maybe needed for others */
+ shutdown(*plogfd, SHUT_RD);
+ }
+
/* For each target, we may have a different facility.
* We can also have a different log level for each message.
* This induces variations in the message header length.
@@ -872,14 +858,27 @@
} while (fac_level && log_ptr > dataptr);
*log_ptr = '<';
- sent = sendto(*plogfd, log_ptr, size - (log_ptr - dataptr),
+ max = size - (log_ptr - dataptr);
+ if (max > logsrv->maxlen)
+ max = logsrv->maxlen;
+
+ /* insert a \n at the end of the message, but save what was
+ * there first because we could have different max lengths
+ * for different log targets.
+ */
+ backup = log_ptr[max - 1];
+ log_ptr[max - 1] = '\n';
+
+ sent = sendto(*plogfd, log_ptr, max,
MSG_DONTWAIT | MSG_NOSIGNAL,
(struct sockaddr *)&logsrv->addr, get_addr_len(&logsrv->addr));
+
+ log_ptr[max - 1] = backup;
+
if (sent < 0) {
Alert("sendto logger #%d failed: %s (errno=%d)\n",
nblogger, strerror(errno), errno);
}
- nblogger++;
}
}
@@ -1619,7 +1618,7 @@
tmplog = update_log_hdr();
size = tmplog - logline;
- size += build_logline(s, tmplog, sizeof(logline) - size, &s->fe->logformat);
+ size += build_logline(s, tmplog, global.max_syslog_len - size, &s->fe->logformat);
if (size > 0) {
__send_log(s->fe, level, logline, size + 1);
s->logs.logwait = 0;
|
[-]
[+]
|
Changed |
haproxy-1.5.3.tar.gz/src/pattern.c
^
|
@@ -529,7 +529,7 @@
list_for_each_entry(lst, &expr->patterns, list) {
pattern = &lst->pat;
- if (regex_exec(pattern->ptr.reg, smp->data.str.str, smp->data.str.len) == 0)
+ if (regex_exec2(pattern->ptr.reg, smp->data.str.str, smp->data.str.len))
return pattern;
}
return NULL;
|
[-]
[+]
|
Changed |
haproxy-1.5.3.tar.gz/src/proto_http.c
^
|
@@ -1029,7 +1029,7 @@
/*
* Capture headers from message starting at <som> according to header list
- * <cap_hdr>, and fill the <idx> structure appropriately.
+ * <cap_hdr>, and fill the <cap> pointers appropriately.
*/
void capture_headers(char *som, struct hdr_idx *idx,
char **cap, struct cap_hdr *cap_hdr)
@@ -1054,7 +1054,7 @@
sov++;
for (h = cap_hdr; h; h = h->next) {
- if ((h->namelen == col - sol) &&
+ if (h->namelen && (h->namelen == col - sol) &&
(strncasecmp(sol, h->name, h->namelen) == 0)) {
if (cap[h->index] == NULL)
cap[h->index] =
@@ -2143,22 +2143,22 @@
{
int q = 1000;
- if (!isdigit(*qvalue))
+ if (!isdigit((unsigned char)*qvalue))
goto out;
q = (*qvalue++ - '0') * 1000;
if (*qvalue++ != '.')
goto out;
- if (!isdigit(*qvalue))
+ if (!isdigit((unsigned char)*qvalue))
goto out;
q += (*qvalue++ - '0') * 100;
- if (!isdigit(*qvalue))
+ if (!isdigit((unsigned char)*qvalue))
goto out;
q += (*qvalue++ - '0') * 10;
- if (!isdigit(*qvalue))
+ if (!isdigit((unsigned char)*qvalue))
goto out;
q += (*qvalue++ - '0') * 1;
out:
@@ -3176,6 +3176,118 @@
#endif
}
+/* Returns the number of characters written to destination,
+ * -1 on internal error and -2 if no replacement took place.
+ */
+static int http_replace_header(struct my_regex *re, char *dst, uint dst_size, char *val, int len,
+ const char *rep_str)
+{
+ if (!regex_exec_match2(re, val, len, MAX_MATCH, pmatch))
+ return -2;
+
+ return exp_replace(dst, dst_size, val, rep_str, pmatch);
+}
+
+/* Returns the number of characters written to destination,
+ * -1 on internal error and -2 if no replacement took place.
+ */
+static int http_replace_value(struct my_regex *re, char *dst, uint dst_size, char *val, int len, char delim,
+ const char *rep_str)
+{
+ char* p = val;
+ char* dst_end = dst + dst_size;
+ char* dst_p = dst;
+
+ for (;;) {
+ char *p_delim;
+
+ /* look for delim. */
+ p_delim = p;
+ while (p_delim < p + len && *p_delim != delim)
+ p_delim++;
+
+ if (regex_exec_match2(re, p, p_delim-p, MAX_MATCH, pmatch)) {
+ int replace_n = exp_replace(dst_p, dst_end - dst_p, p, rep_str, pmatch);
+
+ if (replace_n < 0)
+ return -1;
+
+ dst_p += replace_n;
+ } else {
+ uint len = p_delim - p;
+
+ if (dst_p + len >= dst_end)
+ return -1;
+
+ memcpy(dst_p, p, len);
+ dst_p += len;
+ }
+
+ if (dst_p >= dst_end)
+ return -1;
+
+ /* end of the replacements. */
+ if (p_delim >= p + len)
+ break;
+
+ /* Next part. */
+ *dst_p++ = delim;
+ p = p_delim + 1;
+ }
+
+ return dst_p - dst;
+}
+
+static int http_transform_header(struct session* s, struct http_msg *msg, const char* name, uint name_len,
+ char* buf, struct hdr_idx* idx, struct list *fmt, struct my_regex *re,
+ struct hdr_ctx* ctx, int action)
+{
+ ctx->idx = 0;
+
+ while (http_find_full_header2(name, name_len, buf, idx, ctx)) {
+ struct hdr_idx_elem *hdr = idx->v + ctx->idx;
+ int delta;
+ char* val = (char*)ctx->line + name_len + 2;
+ char* val_end = (char*)ctx->line + hdr->len;
+ char* reg_dst_buf;
+ uint reg_dst_buf_size;
+ int n_replaced;
+
+ trash.len = build_logline(s, trash.str, trash.size, fmt);
+
+ if (trash.len >= trash.size - 1)
+ return -1;
+
+ reg_dst_buf = trash.str + trash.len + 1;
+ reg_dst_buf_size = trash.size - trash.len - 1;
+
+ switch (action) {
+ case HTTP_REQ_ACT_REPLACE_VAL:
+ case HTTP_RES_ACT_REPLACE_VAL:
+ n_replaced = http_replace_value(re, reg_dst_buf, reg_dst_buf_size, val, val_end-val, ',', trash.str);
+ break;
+ case HTTP_REQ_ACT_REPLACE_HDR:
+ case HTTP_RES_ACT_REPLACE_HDR:
+ n_replaced = http_replace_header(re, reg_dst_buf, reg_dst_buf_size, val, val_end-val, trash.str);
+ break;
+ default: /* impossible */
+ return -1;
+ }
+
+ switch (n_replaced) {
+ case -1: return -1;
+ case -2: continue;
+ }
+
+ delta = buffer_replace2(msg->chn->buf, val, val_end, reg_dst_buf, n_replaced);
+
+ hdr->len += delta;
+ http_msg_move_end(msg, delta);
+ }
+
+ return 0;
+}
+
/* Executes the http-request rules <rules> for session <s>, proxy <px> and
* transaction <txn>. Returns the verdict of the first rule that prevents
* further processing of the request (auth, deny, ...), and defaults to
@@ -3265,6 +3377,14 @@
s->logs.level = rule->arg.loglevel;
break;
+ case HTTP_REQ_ACT_REPLACE_HDR:
+ case HTTP_REQ_ACT_REPLACE_VAL:
+ if (http_transform_header(s, &txn->req, rule->arg.hdr_add.name, rule->arg.hdr_add.name_len,
+ txn->req.chn->buf->p, &txn->hdr_idx, &rule->arg.hdr_add.fmt,
+ &rule->arg.hdr_add.re, &ctx, rule->action))
+ return HTTP_RULE_RES_BADREQ;
+ break;
+
case HTTP_REQ_ACT_DEL_HDR:
case HTTP_REQ_ACT_SET_HDR:
ctx.idx = 0;
@@ -3446,6 +3566,14 @@
s->logs.level = rule->arg.loglevel;
break;
+ case HTTP_RES_ACT_REPLACE_HDR:
+ case HTTP_RES_ACT_REPLACE_VAL:
+ if (http_transform_header(s, &txn->rsp, rule->arg.hdr_add.name, rule->arg.hdr_add.name_len,
+ txn->rsp.chn->buf->p, &txn->hdr_idx, &rule->arg.hdr_add.fmt,
+ &rule->arg.hdr_add.re, &ctx, rule->action))
+ return NULL; /* note: we should report an error here */
+ break;
+
case HTTP_RES_ACT_DEL_HDR:
case HTTP_RES_ACT_SET_HDR:
ctx.idx = 0;
@@ -4680,7 +4808,6 @@
s->logs.t_close = tv_ms_elapsed(&s->logs.tv_accept, &now);
session_process_counters(s);
- session_stop_content_counters(s);
if (s->txn.status) {
int n;
@@ -4714,6 +4841,10 @@
s->do_log(s);
}
+ /* stop tracking content-based counters */
+ session_stop_content_counters(s);
+ session_update_time_stats(s);
+
s->logs.accept_date = date; /* user-visible date for logging */
s->logs.tv_accept = now; /* corrected date for internal use */
tv_zero(&s->logs.tv_request);
@@ -5175,13 +5306,6 @@
*/
msg->msg_state = HTTP_MSG_ERROR;
http_resync_states(s);
-
- if (req->flags & CF_READ_TIMEOUT)
- goto cli_timeout;
-
- if (req->flags & CF_WRITE_TIMEOUT)
- goto srv_timeout;
-
return 1;
}
@@ -5191,7 +5315,7 @@
* an "Expect: 100-continue" header.
*/
- if (msg->sov) {
+ if (msg->sov > 0) {
/* we have msg->sov which points to the first byte of message
* body, and req->buf.p still points to the beginning of the
* message. We forward the headers now, as we don't need them
@@ -5305,6 +5429,8 @@
* such as last chunk of data or trailers.
*/
b_adv(req->buf, msg->next);
+ if (unlikely(!(s->rep->flags & CF_READ_ATTACHED)))
+ msg->sov -= msg->next;
msg->next = 0;
/* for keep-alive we don't want to forward closes on DONE */
@@ -5348,11 +5474,6 @@
channel_auto_read(req);
}
- /* if we received everything, we don't want to expire anymore */
- if (msg->msg_state == HTTP_MSG_DONE) {
- req->flags |= CF_READ_NOEXP;
- req->rex = TICK_ETERNITY;
- }
return 0;
}
}
@@ -5360,6 +5481,9 @@
missing_data:
/* we may have some pending data starting at req->buf->p */
b_adv(req->buf, msg->next);
+ if (unlikely(!(s->rep->flags & CF_READ_ATTACHED)))
+ msg->sov -= msg->next + MIN(msg->chunk_len, req->buf->i);
+
msg->next = 0;
msg->chunk_len -= channel_forward(req, msg->chunk_len);
@@ -5462,68 +5586,6 @@
s->flags |= SN_FINST_D;
}
return 0;
-
- cli_timeout:
- if (!(s->flags & SN_ERR_MASK))
- s->flags |= SN_ERR_CLITO;
-
- if (!(s->flags & SN_FINST_MASK)) {
- if (txn->rsp.msg_state < HTTP_MSG_ERROR)
- s->flags |= SN_FINST_H;
- else
- s->flags |= SN_FINST_D;
- }
-
- if (txn->status > 0) {
- /* Don't send any error message if something was already sent */
- stream_int_retnclose(req->prod, NULL);
- }
- else {
- txn->status = 408;
- stream_int_retnclose(req->prod, http_error_message(s, HTTP_ERR_408));
- }
-
- msg->msg_state = HTTP_MSG_ERROR;
- req->analysers = 0;
- s->rep->analysers = 0; /* we're in data phase, we want to abort both directions */
-
- session_inc_http_err_ctr(s);
- s->fe->fe_counters.failed_req++;
- s->be->be_counters.failed_req++;
- if (s->listener->counters)
- s->listener->counters->failed_req++;
- return 0;
-
- srv_timeout:
- if (!(s->flags & SN_ERR_MASK))
- s->flags |= SN_ERR_SRVTO;
-
- if (!(s->flags & SN_FINST_MASK)) {
- if (txn->rsp.msg_state < HTTP_MSG_ERROR)
- s->flags |= SN_FINST_H;
- else
- s->flags |= SN_FINST_D;
- }
-
- if (txn->status > 0) {
- /* Don't send any error message if something was already sent */
- stream_int_retnclose(req->prod, NULL);
- }
- else {
- txn->status = 504;
- stream_int_retnclose(req->prod, http_error_message(s, HTTP_ERR_504));
- }
-
- msg->msg_state = HTTP_MSG_ERROR;
- req->analysers = 0;
- s->rep->analysers = 0; /* we're in data phase, we want to abort both directions */
-
- s->be->be_counters.failed_resp++;
- if (objt_server(s->target)) {
- objt_server(s->target)->counters.failed_resp++;
- health_adjust(objt_server(s->target), HANA_STATUS_HTTP_READ_TIMEOUT);
- }
- return 0;
}
/* This stream analyser waits for a complete HTTP response. It returns 1 if the
@@ -5691,11 +5753,8 @@
return 0;
}
- /* read/write timeout : return a 504 to the client.
- * The write timeout may happen when we're uploading POST
- * data that the server is not consuming fast enough.
- */
- else if (rep->flags & (CF_READ_TIMEOUT|CF_WRITE_TIMEOUT)) {
+ /* read timeout : return a 504 to the client. */
+ else if (rep->flags & CF_READ_TIMEOUT) {
if (msg->err_pos >= 0)
http_capture_bad_message(&s->be->invalid_rep, s, msg, msg->msg_state, s->fe);
else if (txn->flags & TX_NOT_FIRST)
@@ -5791,12 +5850,6 @@
return 0;
}
- /* we don't want to expire on the server side first until the client
- * has sent all the expected message body.
- */
- if (txn->req.msg_state >= HTTP_MSG_BODY && txn->req.msg_state < HTTP_MSG_DONE)
- rep->flags |= CF_READ_NOEXP;
-
channel_dont_close(rep);
rep->flags |= CF_READ_DONTWAIT; /* try to get back here ASAP */
return 0;
@@ -6445,7 +6498,7 @@
/* in most states, we should abort in case of early close */
channel_auto_close(res);
- if (msg->sov) {
+ if (msg->sov > 0) {
/* we have msg->sov which points to the first byte of message
* body, and res->buf.p still points to the beginning of the
* message. We forward the headers now, as we don't need them
@@ -6612,12 +6665,6 @@
}
return 1;
}
-
- /* if we received everything, we don't want to expire anymore */
- if (msg->msg_state == HTTP_MSG_DONE) {
- res->flags |= CF_READ_NOEXP;
- res->rex = TICK_ETERNITY;
- }
return 0;
}
}
@@ -6744,7 +6791,6 @@
*/
int apply_filter_to_req_headers(struct session *s, struct channel *req, struct hdr_exp *exp)
{
- char term;
char *cur_ptr, *cur_end, *cur_next;
int cur_idx, old_idx, last_hdr;
struct http_txn *txn = &s->txn;
@@ -6778,15 +6824,7 @@
* and the next header starts at cur_next.
*/
- /* The annoying part is that pattern matching needs
- * that we modify the contents to null-terminate all
- * strings before testing them.
- */
-
- term = *cur_end;
- *cur_end = '\0';
-
- if (regexec(exp->preg, cur_ptr, MAX_MATCH, pmatch, 0) == 0) {
+ if (regex_exec_match2(exp->preg, cur_ptr, cur_end-cur_ptr, MAX_MATCH, pmatch)) {
switch (exp->action) {
case ACT_SETBE:
/* It is not possible to jump a second time.
@@ -6847,8 +6885,6 @@
}
}
- if (cur_end)
- *cur_end = term; /* restore the string terminator */
/* keep the link from this header to next one in case of later
* removal of next header.
@@ -6867,7 +6903,6 @@
*/
int apply_filter_to_req_line(struct session *s, struct channel *req, struct hdr_exp *exp)
{
- char term;
char *cur_ptr, *cur_end;
int done;
struct http_txn *txn = &s->txn;
@@ -6890,15 +6925,7 @@
/* Now we have the request line between cur_ptr and cur_end */
- /* The annoying part is that pattern matching needs
- * that we modify the contents to null-terminate all
- * strings before testing them.
- */
-
- term = *cur_end;
- *cur_end = '\0';
-
- if (regexec(exp->preg, cur_ptr, MAX_MATCH, pmatch, 0) == 0) {
+ if (regex_exec_match2(exp->preg, cur_ptr, cur_end-cur_ptr, MAX_MATCH, pmatch)) {
switch (exp->action) {
case ACT_SETBE:
/* It is not possible to jump a second time.
@@ -6929,7 +6956,6 @@
break;
case ACT_REPLACE:
- *cur_end = term; /* restore the string terminator */
trash.len = exp_replace(trash.str, trash.size, cur_ptr, exp->replace, pmatch);
if (trash.len < 0)
return -1;
@@ -6958,7 +6984,6 @@
return 1;
}
}
- *cur_end = term; /* restore the string terminator */
return done;
}
@@ -7628,7 +7653,6 @@
*/
int apply_filter_to_resp_headers(struct session *s, struct channel *rtr, struct hdr_exp *exp)
{
- char term;
char *cur_ptr, *cur_end, *cur_next;
int cur_idx, old_idx, last_hdr;
struct http_txn *txn = &s->txn;
@@ -7661,15 +7685,7 @@
* and the next header starts at cur_next.
*/
- /* The annoying part is that pattern matching needs
- * that we modify the contents to null-terminate all
- * strings before testing them.
- */
-
- term = *cur_end;
- *cur_end = '\0';
-
- if (regexec(exp->preg, cur_ptr, MAX_MATCH, pmatch, 0) == 0) {
+ if (regex_exec_match2(exp->preg, cur_ptr, cur_end-cur_ptr, MAX_MATCH, pmatch)) {
switch (exp->action) {
case ACT_ALLOW:
txn->flags |= TX_SVALLOW;
@@ -7712,8 +7728,6 @@
}
}
- if (cur_end)
- *cur_end = term; /* restore the string terminator */
/* keep the link from this header to next one in case of later
* removal of next header.
@@ -7730,7 +7744,6 @@
*/
int apply_filter_to_sts_line(struct session *s, struct channel *rtr, struct hdr_exp *exp)
{
- char term;
char *cur_ptr, *cur_end;
int done;
struct http_txn *txn = &s->txn;
@@ -7753,15 +7766,7 @@
/* Now we have the status line between cur_ptr and cur_end */
- /* The annoying part is that pattern matching needs
- * that we modify the contents to null-terminate all
- * strings before testing them.
- */
-
- term = *cur_end;
- *cur_end = '\0';
-
- if (regexec(exp->preg, cur_ptr, MAX_MATCH, pmatch, 0) == 0) {
+ if (regex_exec_match2(exp->preg, cur_ptr, cur_end-cur_ptr, MAX_MATCH, pmatch)) {
switch (exp->action) {
case ACT_ALLOW:
txn->flags |= TX_SVALLOW;
@@ -7774,7 +7779,6 @@
break;
case ACT_REPLACE:
- *cur_end = term; /* restore the string terminator */
trash.len = exp_replace(trash.str, trash.size, cur_ptr, exp->replace, pmatch);
if (trash.len < 0)
return -1;
@@ -7803,7 +7807,6 @@
return 1;
}
}
- *cur_end = term; /* restore the string terminator */
return done;
}
@@ -8757,7 +8760,19 @@
s->rep->analyse_exp = TICK_ETERNITY;
}
-void free_http_req_rules(struct list *r) {
+void free_http_res_rules(struct list *r)
+{
+ struct http_res_rule *tr, *pr;
+
+ list_for_each_entry_safe(pr, tr, r, list) {
+ LIST_DEL(&pr->list);
+ regex_free(&pr->arg.hdr_add.re);
+ free(pr);
+ }
+}
+
+void free_http_req_rules(struct list *r)
+{
struct http_req_rule *tr, *pr;
list_for_each_entry_safe(pr, tr, r, list) {
@@ -8765,6 +8780,7 @@
if (pr->action == HTTP_REQ_ACT_AUTH)
free(pr->arg.auth.realm);
+ regex_free(&pr->arg.hdr_add.re);
free(pr);
}
}
@@ -8775,6 +8791,7 @@
struct http_req_rule *rule;
struct http_req_action_kw *custom = NULL;
int cur_arg;
+ char *error;
rule = (struct http_req_rule*)calloc(1, sizeof(struct http_req_rule));
if (!rule) {
@@ -8907,6 +8924,38 @@
proxy->conf.lfs_file = strdup(proxy->conf.args.file);
proxy->conf.lfs_line = proxy->conf.args.line;
cur_arg += 2;
+ } else if (strcmp(args[0], "replace-header") == 0 || strcmp(args[0], "replace-value") == 0) {
+ rule->action = args[0][8] == 'h' ? HTTP_REQ_ACT_REPLACE_HDR : HTTP_REQ_ACT_REPLACE_VAL;
+ cur_arg = 1;
+
+ if (!*args[cur_arg] || !*args[cur_arg+1] || !*args[cur_arg+2] ||
+ (*args[cur_arg+3] && strcmp(args[cur_arg+3], "if") != 0 && strcmp(args[cur_arg+3], "unless") != 0)) {
+ Alert("parsing [%s:%d]: 'http-request %s' expects exactly 3 arguments.\n",
+ file, linenum, args[0]);
+ goto out_err;
+ }
+
+ rule->arg.hdr_add.name = strdup(args[cur_arg]);
+ rule->arg.hdr_add.name_len = strlen(rule->arg.hdr_add.name);
+ LIST_INIT(&rule->arg.hdr_add.fmt);
+
+ error = NULL;
+ if (!regex_comp(args[cur_arg + 1], &rule->arg.hdr_add.re, 1, 1, &error)) {
+ Alert("parsing [%s:%d] : '%s' : %s.\n", file, linenum,
+ args[cur_arg + 1], error);
+ free(error);
+ goto out_err;
+ }
+
+ proxy->conf.args.ctx = ARGC_HRQ;
+ parse_logformat_string(args[cur_arg + 2], proxy, &rule->arg.hdr_add.fmt, LOG_OPT_HTTP,
+ (proxy->cap & PR_CAP_FE) ? SMP_VAL_FE_HRQ_HDR : SMP_VAL_BE_HRQ_HDR,
+ file, linenum);
+
+ free(proxy->conf.lfs_file);
+ proxy->conf.lfs_file = strdup(proxy->conf.args.file);
+ proxy->conf.lfs_line = proxy->conf.args.line;
+ cur_arg += 3;
} else if (strcmp(args[0], "del-header") == 0) {
rule->action = HTTP_REQ_ACT_DEL_HDR;
cur_arg = 1;
@@ -9073,7 +9122,7 @@
goto out_err;
}
} else {
- Alert("parsing [%s:%d]: 'http-request' expects 'allow', 'deny', 'auth', 'redirect', 'tarpit', 'add-header', 'set-header', 'set-nice', 'set-tos', 'set-mark', 'set-log-level', 'add-acl', 'del-acl', 'del-map', 'set-map', but got '%s'%s.\n",
+ Alert("parsing [%s:%d]: 'http-request' expects 'allow', 'deny', 'auth', 'redirect', 'tarpit', 'add-header', 'set-header', 'replace-header', 'replace-value', 'set-nice', 'set-tos', 'set-mark', 'set-log-level', 'add-acl', 'del-acl', 'del-map', 'set-map', but got '%s'%s.\n",
file, linenum, args[0], *args[0] ? "" : " (missing argument)");
goto out_err;
}
@@ -9109,6 +9158,7 @@
struct http_res_rule *rule;
struct http_res_action_kw *custom = NULL;
int cur_arg;
+ char *error;
rule = calloc(1, sizeof(*rule));
if (!rule) {
@@ -9226,6 +9276,38 @@
proxy->conf.lfs_file = strdup(proxy->conf.args.file);
proxy->conf.lfs_line = proxy->conf.args.line;
cur_arg += 2;
+ } else if (strcmp(args[0], "replace-header") == 0 || strcmp(args[0], "replace-value") == 0) {
+ rule->action = args[0][8] == 'h' ? HTTP_RES_ACT_REPLACE_HDR : HTTP_RES_ACT_REPLACE_VAL;
+ cur_arg = 1;
+
+ if (!*args[cur_arg] || !*args[cur_arg+1] || !*args[cur_arg+2] ||
+ (*args[cur_arg+3] && strcmp(args[cur_arg+2], "if") != 0 && strcmp(args[cur_arg+2], "unless") != 0)) {
+ Alert("parsing [%s:%d]: 'http-request %s' expects exactly 3 arguments.\n",
+ file, linenum, args[0]);
+ goto out_err;
+ }
+
+ rule->arg.hdr_add.name = strdup(args[cur_arg]);
+ rule->arg.hdr_add.name_len = strlen(rule->arg.hdr_add.name);
+ LIST_INIT(&rule->arg.hdr_add.fmt);
+
+ error = NULL;
+ if (!regex_comp(args[cur_arg + 1], &rule->arg.hdr_add.re, 1, 1, &error)) {
+ Alert("parsing [%s:%d] : '%s' : %s.\n", file, linenum,
+ args[cur_arg + 1], error);
+ free(error);
+ goto out_err;
+ }
+
+ proxy->conf.args.ctx = ARGC_HRQ;
+ parse_logformat_string(args[cur_arg + 2], proxy, &rule->arg.hdr_add.fmt, LOG_OPT_HTTP,
+ (proxy->cap & PR_CAP_BE) ? SMP_VAL_BE_HRS_HDR : SMP_VAL_FE_HRS_HDR,
+ file, linenum);
+
+ free(proxy->conf.lfs_file);
+ proxy->conf.lfs_file = strdup(proxy->conf.args.file);
+ proxy->conf.lfs_line = proxy->conf.args.line;
+ cur_arg += 3;
} else if (strcmp(args[0], "del-header") == 0) {
rule->action = HTTP_RES_ACT_DEL_HDR;
cur_arg = 1;
@@ -9376,7 +9458,7 @@
goto out_err;
}
} else {
- Alert("parsing [%s:%d]: 'http-response' expects 'allow', 'deny', 'redirect', 'add-header', 'del-header', 'set-header', 'set-nice', 'set-tos', 'set-mark', 'set-log-level', 'del-acl', 'add-acl', 'del-map', 'set-map', but got '%s'%s.\n",
+ Alert("parsing [%s:%d]: 'http-response' expects 'allow', 'deny', 'redirect', 'add-header', 'del-header', 'set-header', 'replace-header', 'replace-value', 'set-nice', 'set-tos', 'set-mark', 'set-log-level', 'del-acl', 'add-acl', 'del-map', 'set-map', but got '%s'%s.\n",
file, linenum, args[0], *args[0] ? "" : " (missing argument)");
goto out_err;
}
@@ -9671,6 +9753,9 @@
return 1;
}
+/* Note: these functinos *do* modify the sample. Even in case of success, at
+ * least the type and uint value are modified.
+ */
#define CHECK_HTTP_MESSAGE_FIRST() \
do { int r = smp_prefetch_http(px, l4, l7, opt, args, smp, 1); if (r <= 0) return r; } while (0)
@@ -10171,6 +10256,7 @@
struct http_txn *txn = l7;
char *ptr, *end, *beg;
struct hdr_ctx ctx;
+ struct chunk *temp;
CHECK_HTTP_MESSAGE_FIRST();
@@ -10179,9 +10265,10 @@
return smp_fetch_path(px, l4, l7, opt, args, smp, kw);
/* OK we have the header value in ctx.line+ctx.val for ctx.vlen bytes */
- memcpy(trash.str, ctx.line + ctx.val, ctx.vlen);
+ temp = get_trash_chunk();
+ memcpy(temp->str, ctx.line + ctx.val, ctx.vlen);
smp->type = SMP_T_STR;
- smp->data.str.str = trash.str;
+ smp->data.str.str = temp->str;
smp->data.str.len = ctx.vlen;
/* now retrieve the path */
@@ -10271,8 +10358,8 @@
return 0;
temp = get_trash_chunk();
- memcpy(temp->str + temp->len, &smp->data.uint, sizeof(smp->data.uint));
- temp->len += sizeof(smp->data.uint);
+ *(unsigned int *)temp->str = htonl(smp->data.uint);
+ temp->len += sizeof(unsigned int);
switch (cli_conn->addr.from.ss_family) {
case AF_INET:
@@ -11144,7 +11231,7 @@
while (1) {
/* Jump spaces, quit if the end is detected. */
- while (al < end && isspace(*al))
+ while (al < end && isspace((unsigned char)*al))
al++;
if (al >= end)
break;
@@ -11153,7 +11240,7 @@
token = al;
/* Look for separator: isspace(), ',' or ';'. Next value if 0 length word. */
- while (al < end && *al != ';' && *al != ',' && !isspace(*al))
+ while (al < end && *al != ';' && *al != ',' && !isspace((unsigned char)*al))
al++;
if (al == token)
goto expect_comma;
@@ -11182,7 +11269,7 @@
look_for_q:
/* Jump spaces, quit if the end is detected. */
- while (al < end && isspace(*al))
+ while (al < end && isspace((unsigned char)*al))
al++;
if (al >= end)
goto process_value;
@@ -11201,7 +11288,7 @@
al++;
/* Jump spaces, process value if the end is detected. */
- while (al < end && isspace(*al))
+ while (al < end && isspace((unsigned char)*al))
al++;
if (al >= end)
goto process_value;
@@ -11212,7 +11299,7 @@
al++;
/* Jump spaces, process value if the end is detected. */
- while (al < end && isspace(*al))
+ while (al < end && isspace((unsigned char)*al))
al++;
if (al >= end)
goto process_value;
@@ -11223,7 +11310,7 @@
al++;
/* Jump spaces, process value if the end is detected. */
- while (al < end && isspace(*al))
+ while (al < end && isspace((unsigned char)*al))
al++;
if (al >= end)
goto process_value;
|
[-]
[+]
|
Changed |
haproxy-1.5.3.tar.gz/src/proto_tcp.c
^
|
@@ -35,6 +35,7 @@
#include <common/standard.h>
#include <types/global.h>
+#include <types/capture.h>
#include <types/server.h>
#include <proto/acl.h>
@@ -79,6 +80,7 @@
.get_src = tcp_get_src,
.get_dst = tcp_get_dst,
.drain = tcp_drain,
+ .pause = tcp_pause_listener,
.listeners = LIST_HEAD_INIT(proto_tcpv4.listeners),
.nb_listeners = 0,
};
@@ -101,6 +103,7 @@
.get_src = tcp_get_src,
.get_dst = tcp_get_dst,
.drain = tcp_drain,
+ .pause = tcp_pause_listener,
.listeners = LIST_HEAD_INIT(proto_tcpv6.listeners),
.nb_listeners = 0,
};
@@ -946,6 +949,22 @@
proto_tcpv6.nb_listeners++;
}
+/* Pause a listener. Returns < 0 in case of failure, 0 if the listener
+ * was totally stopped, or > 0 if correctly paused.
+ */
+int tcp_pause_listener(struct listener *l)
+{
+ if (shutdown(l->fd, SHUT_WR) != 0)
+ return -1; /* Solaris dies here */
+
+ if (listen(l->fd, l->backlog ? l->backlog : l->maxconn) != 0)
+ return -1; /* OpenBSD dies here */
+
+ if (shutdown(l->fd, SHUT_RD) != 0)
+ return -1; /* should always be OK */
+ return 1;
+}
+
/* This function performs the TCP request analysis on the current request. It
* returns 1 if the processing can continue on next analysers, or zero if it
* needs more data, encounters an error, or wants to immediately abort the
@@ -990,13 +1009,8 @@
if (rule->cond) {
ret = acl_exec_cond(rule->cond, s->be, s, &s->txn, SMP_OPT_DIR_REQ | partial);
- if (ret == ACL_TEST_MISS) {
- channel_dont_connect(req);
- /* just set the request timeout once at the beginning of the request */
- if (!tick_isset(req->analyse_exp) && s->be->tcp_req.inspect_delay)
- req->analyse_exp = tick_add(now_ms, s->be->tcp_req.inspect_delay);
- return 0;
- }
+ if (ret == ACL_TEST_MISS)
+ goto missing_data;
ret = acl_pass(ret);
if (rule->cond->pol == ACL_COND_UNLESS)
@@ -1026,12 +1040,16 @@
* applies.
*/
struct stktable_key *key;
+ struct sample smp;
if (stkctr_entry(&s->stkctr[tcp_trk_idx(rule->action)]))
continue;
t = rule->act_prm.trk_ctr.table.t;
- key = stktable_fetch_key(t, s->be, s, &s->txn, SMP_OPT_DIR_REQ|SMP_OPT_FINAL, rule->act_prm.trk_ctr.expr);
+ key = stktable_fetch_key(t, s->be, s, &s->txn, SMP_OPT_DIR_REQ | partial, rule->act_prm.trk_ctr.expr, &smp);
+
+ if (smp.flags & SMP_F_MAY_CHANGE)
+ goto missing_data;
if (key && (ts = stktable_get_entry(t, key))) {
session_track_stkctr(&s->stkctr[tcp_trk_idx(rule->action)], t, ts);
@@ -1040,6 +1058,32 @@
stkctr_set_flags(&s->stkctr[tcp_trk_idx(rule->action)], STKCTR_TRACK_BACKEND);
}
}
+ else if (rule->action == TCP_ACT_CAPTURE) {
+ struct sample *key;
+ struct cap_hdr *h = rule->act_prm.cap.hdr;
+ char **cap = s->txn.req.cap;
+ int len;
+
+ key = sample_fetch_string(s->be, s, &s->txn, SMP_OPT_DIR_REQ | partial, rule->act_prm.cap.expr);
+ if (!key)
+ continue;
+
+ if (key->flags & SMP_F_MAY_CHANGE)
+ goto missing_data;
+
+ if (cap[h->index] == NULL)
+ cap[h->index] = pool_alloc2(h->pool);
+
+ if (cap[h->index] == NULL) /* no more capture memory */
+ continue;
+
+ len = key->data.str.len;
+ if (len > h->len)
+ len = h->len;
+
+ memcpy(cap[h->index], key->data.str.str, len);
+ cap[h->index][len] = 0;
+ }
else {
/* otherwise accept */
break;
@@ -1053,6 +1097,14 @@
req->analysers &= ~an_bit;
req->analyse_exp = TICK_ETERNITY;
return 1;
+
+ missing_data:
+ channel_dont_connect(req);
+ /* just set the request timeout once at the beginning of the request */
+ if (!tick_isset(req->analyse_exp) && s->be->tcp_req.inspect_delay)
+ req->analyse_exp = tick_add(now_ms, s->be->tcp_req.inspect_delay);
+ return 0;
+
}
/* This function performs the TCP response analysis on the current response. It
@@ -1198,7 +1250,7 @@
continue;
t = rule->act_prm.trk_ctr.table.t;
- key = stktable_fetch_key(t, s->be, s, &s->txn, SMP_OPT_DIR_REQ|SMP_OPT_FINAL, rule->act_prm.trk_ctr.expr);
+ key = stktable_fetch_key(t, s->be, s, &s->txn, SMP_OPT_DIR_REQ|SMP_OPT_FINAL, rule->act_prm.trk_ctr.expr, NULL);
if (key && (ts = stktable_get_entry(t, key)))
session_track_stkctr(&s->stkctr[tcp_trk_idx(rule->action)], t, ts);
@@ -1287,6 +1339,92 @@
arg++;
rule->action = TCP_ACT_REJECT;
}
+ else if (strcmp(args[arg], "capture") == 0) {
+ struct sample_expr *expr;
+ struct cap_hdr *hdr;
+ int kw = arg;
+ int len = 0;
+
+ if (!(curpx->cap & PR_CAP_FE)) {
+ memprintf(err,
+ "'%s %s %s' : proxy '%s' has no frontend capability",
+ args[0], args[1], args[kw], curpx->id);
+ return -1;
+ }
+
+ if (!(where & SMP_VAL_FE_REQ_CNT)) {
+ memprintf(err,
+ "'%s %s' is not allowed in '%s %s' rules in %s '%s'",
+ args[arg], args[arg+1], args[0], args[1], proxy_type_str(curpx), curpx->id);
+ return -1;
+ }
+
+ arg++;
+
+ curpx->conf.args.ctx = ARGC_CAP;
+ expr = sample_parse_expr(args, &arg, file, line, err, &curpx->conf.args);
+ if (!expr) {
+ memprintf(err,
+ "'%s %s %s' : %s",
+ args[0], args[1], args[kw], *err);
+ return -1;
+ }
+
+ if (!(expr->fetch->val & where)) {
+ memprintf(err,
+ "'%s %s %s' : fetch method '%s' extracts information from '%s', none of which is available here",
+ args[0], args[1], args[kw], args[arg-1], sample_src_names(expr->fetch->use));
+ free(expr);
+ return -1;
+ }
+
+ if (strcmp(args[arg], "len") == 0) {
+ arg++;
+ if (!args[arg]) {
+ memprintf(err,
+ "'%s %s %s' : missing length value",
+ args[0], args[1], args[kw]);
+ free(expr);
+ return -1;
+ }
+ /* we copy the table name for now, it will be resolved later */
+ len = atoi(args[arg]);
+ if (len <= 0) {
+ memprintf(err,
+ "'%s %s %s' : length must be > 0",
+ args[0], args[1], args[kw]);
+ free(expr);
+ return -1;
+ }
+ arg++;
+ }
+
+ if (!len) {
+ memprintf(err,
+ "'%s %s %s' : a positive 'len' argument is mandatory",
+ args[0], args[1], args[kw]);
+ free(expr);
+ return -1;
+ }
+
+ hdr = calloc(sizeof(struct cap_hdr), 1);
+ hdr->next = curpx->req_cap;
+ hdr->name = NULL; /* not a header capture */
+ hdr->namelen = 0;
+ hdr->len = len;
+ hdr->pool = create_pool("caphdr", hdr->len + 1, MEM_F_SHARED);
+ hdr->index = curpx->nb_req_cap++;
+
+ curpx->req_cap = hdr;
+ curpx->to_log |= LW_REQHDR;
+
+ /* check if we need to allocate an hdr_idx struct for HTTP parsing */
+ curpx->http_needed |= !!(expr->fetch->use & SMP_USE_HTTP_ANY);
+
+ rule->act_prm.cap.expr = expr;
+ rule->act_prm.cap.hdr = hdr;
+ rule->action = TCP_ACT_CAPTURE;
+ }
else if (strncmp(args[arg], "track-sc", 8) == 0 &&
args[arg][9] == '\0' && args[arg][8] >= '0' &&
args[arg][8] <= '0' + MAX_SESS_STKCTR) { /* track-sc 0..9 */
|
[-]
[+]
|
Changed |
haproxy-1.5.3.tar.gz/src/proto_uxst.c
^
|
@@ -68,6 +68,7 @@
.disable_all = disable_all_listeners,
.get_src = uxst_get_src,
.get_dst = uxst_get_dst,
+ .pause = uxst_pause_listener,
.listeners = LIST_HEAD_INIT(proto_unix.listeners),
.nb_listeners = 0,
};
@@ -166,9 +167,11 @@
const char *path;
int ext, ready;
socklen_t ready_len;
-
+ int err;
int ret;
+ err = ERR_NONE;
+
/* ensure we never return garbage */
if (errlen)
*errmsg = 0;
@@ -191,29 +194,34 @@
if (path[0]) {
ret = snprintf(tempname, MAXPATHLEN, "%s.%d.tmp", path, pid);
if (ret < 0 || ret >= MAXPATHLEN) {
+ err |= ERR_FATAL | ERR_ALERT;
msg = "name too long for UNIX socket";
goto err_return;
}
ret = snprintf(backname, MAXPATHLEN, "%s.%d.bak", path, pid);
if (ret < 0 || ret >= MAXPATHLEN) {
+ err |= ERR_FATAL | ERR_ALERT;
msg = "name too long for UNIX socket";
goto err_return;
}
/* 2. clean existing orphaned entries */
if (unlink(tempname) < 0 && errno != ENOENT) {
+ err |= ERR_FATAL | ERR_ALERT;
msg = "error when trying to unlink previous UNIX socket";
goto err_return;
}
if (unlink(backname) < 0 && errno != ENOENT) {
+ err |= ERR_FATAL | ERR_ALERT;
msg = "error when trying to unlink previous UNIX socket";
goto err_return;
}
/* 3. backup existing socket */
if (link(path, backname) < 0 && errno != ENOENT) {
+ err |= ERR_FATAL | ERR_ALERT;
msg = "error when trying to preserve previous UNIX socket";
goto err_return;
}
@@ -231,24 +239,35 @@
fd = socket(PF_UNIX, SOCK_STREAM, 0);
if (fd < 0) {
+ err |= ERR_FATAL | ERR_ALERT;
msg = "cannot create UNIX socket";
goto err_unlink_back;
}
fd_ready:
if (fd >= global.maxsock) {
+ err |= ERR_FATAL | ERR_ALERT;
msg = "socket(): not enough free sockets, raise -n argument";
goto err_unlink_temp;
}
if (fcntl(fd, F_SETFL, O_NONBLOCK) == -1) {
+ err |= ERR_FATAL | ERR_ALERT;
msg = "cannot make UNIX socket non-blocking";
goto err_unlink_temp;
}
if (!ext && bind(fd, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
/* note that bind() creates the socket <tempname> on the file system */
- msg = "cannot bind UNIX socket";
+ if (errno == EADDRINUSE) {
+ /* the old process might still own it, let's retry */
+ err |= ERR_RETRYABLE | ERR_ALERT;
+ msg = "cannot listen to socket";
+ }
+ else {
+ err |= ERR_FATAL | ERR_ALERT;
+ msg = "cannot bind UNIX socket";
+ }
goto err_unlink_temp;
}
@@ -261,6 +280,7 @@
(((listener->bind_conf->ux.uid != -1 || listener->bind_conf->ux.gid != -1) &&
(chown(tempname, listener->bind_conf->ux.uid, listener->bind_conf->ux.gid) == -1)) ||
(listener->bind_conf->ux.mode != 0 && chmod(tempname, listener->bind_conf->ux.mode) == -1))) {
+ err |= ERR_FATAL | ERR_ALERT;
msg = "cannot change UNIX socket ownership";
goto err_unlink_temp;
}
@@ -272,6 +292,7 @@
if (!(ext && ready) && /* only listen if not already done by external process */
listen(fd, listener->backlog ? listener->backlog : listener->maxconn) < 0) {
+ err |= ERR_FATAL | ERR_ALERT;
msg = "cannot listen to UNIX socket";
goto err_unlink_temp;
}
@@ -281,6 +302,7 @@
* backname. Abstract sockets are not renamed.
*/
if (!ext && path[0] && rename(tempname, path) < 0) {
+ err |= ERR_FATAL | ERR_ALERT;
msg = "cannot switch final and temporary UNIX sockets";
goto err_rename;
}
@@ -303,17 +325,18 @@
fd_insert(fd);
fdtab[fd].iocb = listener->proto->accept;
fdtab[fd].owner = listener; /* reference the listener instead of a task */
- return ERR_NONE;
+ return err;
+
err_rename:
ret = rename(backname, path);
if (ret < 0 && errno == ENOENT)
unlink(path);
err_unlink_temp:
- if (!ext)
+ if (!ext && path[0])
unlink(tempname);
close(fd);
err_unlink_back:
- if (!ext)
+ if (!ext && path[0])
unlink(backname);
err_return:
if (msg && errlen) {
@@ -322,7 +345,7 @@
else
snprintf(errmsg, errlen, "%s [fd %d]", msg, fd);
}
- return ERR_FATAL | ERR_ALERT;
+ return err;
}
/* This function closes the UNIX sockets for the specified listener.
@@ -351,6 +374,20 @@
proto_unix.nb_listeners++;
}
+/* Pause a listener. Returns < 0 in case of failure, 0 if the listener
+ * was totally stopped, or > 0 if correctly paused. Nothing is done for
+ * plain unix sockets since currently it's the new process which handles
+ * the renaming. Abstract sockets are completely unbound.
+ */
+int uxst_pause_listener(struct listener *l)
+{
+ if (((struct sockaddr_un *)&l->addr)->sun_path[0])
+ return 1;
+
+ unbind_listener(l);
+ return 0;
+}
+
/*
* This function initiates a UNIX connection establishment to the target assigned
|
[-]
[+]
|
Changed |
haproxy-1.5.3.tar.gz/src/regex.c
^
|
@@ -15,6 +15,7 @@
#include <string.h>
#include <common/config.h>
+#include <common/defaults.h>
#include <common/regex.h>
#include <common/standard.h>
#include <proto/log.h>
@@ -22,7 +23,7 @@
/* regex trash buffer used by various regex tests */
regmatch_t pmatch[MAX_MATCH]; /* rm_so, rm_eo for regular expressions */
-int exp_replace(char *dst, uint dst_size, char *src, const char *str, const regmatch_t *matches)
+int exp_replace(char *dst, unsigned int dst_size, char *src, const char *str, const regmatch_t *matches)
{
char *old_dst = dst;
char* dst_end = dst + dst_size;
@@ -123,7 +124,7 @@
/* returns the pointer to an error in the replacement string, or NULL if OK */
-const char *chain_regex(struct hdr_exp **head, const regex_t *preg,
+const char *chain_regex(struct hdr_exp **head, struct my_regex *preg,
int action, const char *replace, void *cond)
{
struct hdr_exp *exp;
@@ -149,9 +150,129 @@
return NULL;
}
+/* This function apply regex. It take const null terminated char as input.
+ * If the function doesn't match, it returns false, else it returns true.
+ * When it is compiled with JIT, this function execute strlen on the subject.
+ */
+int regex_exec_match(const struct my_regex *preg, const char *subject,
+ size_t nmatch, regmatch_t pmatch[]) {
+#if defined(USE_PCRE) || defined(USE_PCRE_JIT)
+ int ret;
+ int matches[MAX_MATCH * 3];
+ int enmatch;
+ int i;
+
+ /* Silently limit the number of allowed matches. max
+ * match i the maximum value for match, in fact this
+ * limit is not applyied.
+ */
+ enmatch = nmatch;
+ if (enmatch > MAX_MATCH)
+ enmatch = MAX_MATCH;
+
+ /* The value returned by pcre_exec() is one more than the highest numbered
+ * pair that has been set. For example, if two substrings have been captured,
+ * the returned value is 3. If there are no capturing subpatterns, the return
+ * value from a successful match is 1, indicating that just the first pair of
+ * offsets has been set.
+ *
+ * It seems that this function returns 0 if it detect more matches than avalaible
+ * space in the matches array.
+ */
+ ret = pcre_exec(preg->reg, preg->extra, subject, strlen(subject), 0, 0, matches, enmatch * 3);
+ if (ret < 0)
+ return 0;
+
+ if (ret == 0)
+ ret = enmatch;
+
+ for (i=0; i<nmatch; i++) {
+ /* Copy offset. */
+ if (i < ret) {
+ pmatch[i].rm_so = matches[(i*2)];
+ pmatch[i].rm_eo = matches[(i*2)+1];
+ continue;
+ }
+ /* Set the unmatvh flag (-1). */
+ pmatch[i].rm_so = -1;
+ pmatch[i].rm_eo = -1;
+ }
+ return 1;
+#else
+ int match;
+ match = regexec(&preg->regex, subject, nmatch, pmatch, 0);
+ if (match == REG_NOMATCH)
+ return 0;
+ return 1;
+#endif
+}
+
+/* This function apply regex. It take a "char *" ans length as input. The
+ * <subject> can be modified during the processing. If the function doesn't
+ * match, it returns false, else it returns true.
+ * When it is compiled with standard POSIX regex or PCRE, this function add
+ * a temporary null chracters at the end of the <subject>. The <subject> must
+ * have a real length of <length> + 1.
+ */
+int regex_exec_match2(const struct my_regex *preg, char *subject, int length,
+ size_t nmatch, regmatch_t pmatch[]) {
+#if defined(USE_PCRE) || defined(USE_PCRE_JIT)
+ int ret;
+ int matches[MAX_MATCH * 3];
+ int enmatch;
+ int i;
+
+ /* Silently limit the number of allowed matches. max
+ * match i the maximum value for match, in fact this
+ * limit is not applyied.
+ */
+ enmatch = nmatch;
+ if (enmatch > MAX_MATCH)
+ enmatch = MAX_MATCH;
+
+ /* The value returned by pcre_exec() is one more than the highest numbered
+ * pair that has been set. For example, if two substrings have been captured,
+ * the returned value is 3. If there are no capturing subpatterns, the return
+ * value from a successful match is 1, indicating that just the first pair of
+ * offsets has been set.
+ *
+ * It seems that this function returns 0 if it detect more matches than avalaible
+ * space in the matches array.
+ */
+ ret = pcre_exec(preg->reg, preg->extra, subject, length, 0, 0, matches, enmatch * 3);
+ if (ret < 0)
+ return 0;
+
+ if (ret == 0)
+ ret = enmatch;
+
+ for (i=0; i<nmatch; i++) {
+ /* Copy offset. */
+ if (i < ret) {
+ pmatch[i].rm_so = matches[(i*2)];
+ pmatch[i].rm_eo = matches[(i*2)+1];
+ continue;
+ }
+ /* Set the unmatvh flag (-1). */
+ pmatch[i].rm_so = -1;
+ pmatch[i].rm_eo = -1;
+ }
+ return 1;
+#else
+ char old_char = subject[length];
+ int match;
+ subject[length] = 0;
+ match = regexec(&preg->regex, subject, nmatch, pmatch, 0);
+ subject[length] = old_char;
+ if (match == REG_NOMATCH)
+ return 0;
+ return 1;
+#endif
+}
+
int regex_comp(const char *str, struct my_regex *regex, int cs, int cap, char **err)
{
-#ifdef USE_PCRE_JIT
+#if defined(USE_PCRE) || defined(USE_PCRE_JIT)
int flags = 0;
const char *error;
int erroffset;
@@ -167,6 +288,7 @@
return 0;
}
+#ifdef USE_PCRE_JIT
regex->extra = pcre_study(regex->reg, PCRE_STUDY_JIT_COMPILE, &error);
if (!regex->extra) {
pcre_free(regex->reg);
@@ -174,6 +296,9 @@
return 0;
}
#else
+ regex->extra = NULL;
+#endif
+#else
int flags = REG_EXTENDED;
if (!cs)
|
[-]
[+]
|
Changed |
haproxy-1.5.3.tar.gz/src/sample.c
^
|
@@ -905,7 +905,7 @@
if (p == NULL) {
p = &temp_smp;
- p->flags = 0;
+ memset(p, 0, sizeof(*p));
}
if (!expr->fetch->process(px, l4, l7, opt, expr->arg_p, p, expr->fetch->kw))
@@ -971,6 +971,7 @@
case ARGC_HRS: where = "in http-response header format string in"; break;
case ARGC_UIF: where = "in unique-id-format string in"; break;
case ARGC_RDR: where = "in redirect format string in"; break;
+ case ARGC_CAP: where = "in capture rule in"; break;
case ARGC_ACL: ctx = "ACL keyword"; break;
}
@@ -1144,19 +1145,28 @@
}
/*
- * Process a fetch + format conversion as defined by the sample expression <expr>
- * on request or response considering the <opt> parameter. The output is always of
- * type string. Returns either NULL if no sample could be extracted, or a pointer
- * to the converted result stored in static temp_smp in format string.
+ * Process a fetch + format conversion as defined by the sample expression
+ * <expr> on request or response considering the <opt> parameter. The output is
+ * always of type string. If a stable sample can be fetched, or an unstable one
+ * when <opt> contains SMP_OPT_FINAL, the sample is converted to a string and
+ * returned without the SMP_F_MAY_CHANGE flag. If an unstable sample is found
+ * and <opt> does not contain SMP_OPT_FINAL, then the sample is returned as-is
+ * with its SMP_F_MAY_CHANGE flag so that the caller can check it and decide to
+ * take actions (eg: wait longer). If a sample could not be found or could not
+ * be converted, NULL is returned.
*/
struct sample *sample_fetch_string(struct proxy *px, struct session *l4, void *l7,
unsigned int opt, struct sample_expr *expr)
{
- struct sample *smp;
+ struct sample *smp = &temp_smp;
- smp = sample_process(px, l4, l7, opt, expr, NULL);
- if (!smp)
+ memset(smp, 0, sizeof(*smp));
+
+ if (!sample_process(px, l4, l7, opt, expr, smp)) {
+ if ((smp->flags & SMP_F_MAY_CHANGE) && !(opt & SMP_OPT_FINAL))
+ return smp;
return NULL;
+ }
if (!sample_casts[smp->type][SMP_T_STR])
return NULL;
@@ -1165,6 +1175,7 @@
return NULL;
smp->type = SMP_T_STR;
+ smp->flags &= ~SMP_F_MAY_CHANGE;
return smp;
}
|
[-]
[+]
|
Changed |
haproxy-1.5.3.tar.gz/src/session.c
^
|
@@ -879,8 +879,15 @@
* we must mark the session unassigned, and eventually clear the DIRECT
* bit to ignore any persistence cookie. We won't count a retry nor a
* redispatch yet, because this will depend on what server is selected.
+ * If the connection is not persistent, the balancing algorithm is not
+ * determinist (round robin) and there is more than one active server,
+ * we accept to perform an immediate redispatch without waiting since
+ * we don't care about this particular server.
*/
- if (objt_server(s->target) && si->conn_retries == 0 &&
+ if (objt_server(s->target) &&
+ (si->conn_retries == 0 ||
+ (!(s->flags & SN_DIRECT) && s->be->srv_act > 1 &&
+ ((s->be->lbprm.algo & BE_LB_KIND) == BE_LB_KIND_RR))) &&
s->be->options & PR_O_REDISP && !(s->flags & SN_FORCE_PRST)) {
sess_change_server(s, NULL);
if (may_dequeue_tasks(objt_server(s->target), s->be))
@@ -899,14 +906,24 @@
/* The error was an asynchronous connection error, and we will
* likely have to retry connecting to the same server, most
* likely leading to the same result. To avoid this, we wait
- * one second before retrying.
+ * MIN(one second, connect timeout) before retrying.
*/
+ int delay = 1000;
+
+ if (s->be->timeout.connect && s->be->timeout.connect < delay)
+ delay = s->be->timeout.connect;
+
if (!si->err_type)
si->err_type = SI_ET_CONN_ERR;
- si->state = SI_ST_TAR;
- si->exp = tick_add(now_ms, MS_TO_TICKS(1000));
+ /* only wait when we're retrying on the same server */
+ if (si->state == SI_ST_ASS ||
+ (s->be->lbprm.algo & BE_LB_KIND) != BE_LB_KIND_RR ||
+ (s->be->srv_act <= 1)) {
+ si->state = SI_ST_TAR;
+ si->exp = tick_add(now_ms, MS_TO_TICKS(delay));
+ }
return 0;
}
return 0;
@@ -1441,7 +1458,7 @@
if (ret) {
struct stktable_key *key;
- key = stktable_fetch_key(rule->table.t, px, s, &s->txn, SMP_OPT_DIR_REQ|SMP_OPT_FINAL, rule->expr);
+ key = stktable_fetch_key(rule->table.t, px, s, &s->txn, SMP_OPT_DIR_REQ|SMP_OPT_FINAL, rule->expr, NULL);
if (!key)
continue;
@@ -1544,7 +1561,7 @@
if (ret) {
struct stktable_key *key;
- key = stktable_fetch_key(rule->table.t, px, s, &s->txn, SMP_OPT_DIR_RES|SMP_OPT_FINAL, rule->expr);
+ key = stktable_fetch_key(rule->table.t, px, s, &s->txn, SMP_OPT_DIR_RES|SMP_OPT_FINAL, rule->expr, NULL);
if (!key)
continue;
@@ -1619,7 +1636,6 @@
unsigned int rq_prod_last, rq_cons_last;
unsigned int rp_cons_last, rp_prod_last;
unsigned int req_ana_back;
- unsigned int rq_oneshot, rp_oneshot;
//DPRINTF(stderr, "%s:%d: cs=%d ss=%d(%d) rqf=0x%08x rpf=0x%08x\n", __FUNCTION__, __LINE__,
// s->si[0].state, s->si[1].state, s->si[1].err_type, s->req->flags, s->rep->flags);
@@ -1627,13 +1643,9 @@
/* this data may be no longer valid, clear it */
memset(&s->txn.auth, 0, sizeof(s->txn.auth));
- /* These flags must explicitly be set every time by the analysers who
- * need them, but we won't always call them (eg: during a connection
- * retry). So we need to keep them and only clear them if we're sure
- * to call the analysers.
- */
- rq_oneshot = s->req->flags & (CF_READ_NOEXP | CF_WAKE_WRITE);
- rp_oneshot = s->rep->flags & (CF_READ_NOEXP | CF_WAKE_WRITE);
+ /* This flag must explicitly be set every time */
+ s->req->flags &= ~(CF_READ_NOEXP|CF_WAKE_WRITE);
+ s->rep->flags &= ~(CF_READ_NOEXP|CF_WAKE_WRITE);
/* Keep a copy of req/rep flags so that we can detect shutdowns */
rqf_last = s->req->flags & ~CF_MASK_ANALYSER;
@@ -1814,8 +1826,6 @@
s->si[1].state != rq_cons_last) {
unsigned int flags = s->req->flags;
- s->req->flags &= ~rq_oneshot;
- rq_oneshot = 0;
if (s->req->prod->state >= SI_ST_EST) {
int max_loops = global.tune.maxpollevents;
unsigned int ana_list;
@@ -1969,13 +1979,11 @@
/* Analyse response */
if (((s->rep->flags & ~rpf_last) & CF_MASK_ANALYSER) ||
- ((s->rep->flags ^ rpf_last) & CF_MASK_STATIC) ||
- s->si[0].state != rp_cons_last ||
- s->si[1].state != rp_prod_last) {
+ (s->rep->flags ^ rpf_last) & CF_MASK_STATIC ||
+ s->si[0].state != rp_cons_last ||
+ s->si[1].state != rp_prod_last) {
unsigned int flags = s->rep->flags;
- s->rep->flags &= ~rp_oneshot;
- rp_oneshot = 0;
if ((s->rep->flags & CF_MASK_ANALYSER) &&
(s->rep->analysers & AN_REQ_WAIT_HTTP)) {
/* Due to HTTP pipelining, the HTTP request analyser might be waiting
@@ -2169,9 +2177,6 @@
channel_auto_close(s->req);
buffer_flush(s->req->buf);
- s->req->flags &= ~rq_oneshot;
- rq_oneshot = 0;
-
/* We'll let data flow between the producer (if still connected)
* to the consumer (which might possibly not be connected yet).
*/
@@ -2327,9 +2332,6 @@
channel_auto_close(s->rep);
buffer_flush(s->rep->buf);
- s->rep->flags &= ~rp_oneshot;
- rp_oneshot = 0;
-
/* We'll let data flow between the producer (if still connected)
* to the consumer.
*/
@@ -2479,6 +2481,20 @@
s->si[0].flags &= ~(SI_FL_ERR|SI_FL_EXP);
s->si[1].flags &= ~(SI_FL_ERR|SI_FL_EXP);
+ /* Trick: if a request is being waiting for the server to respond,
+ * and if we know the server can timeout, we don't want the timeout
+ * to expire on the client side first, but we're still interested
+ * in passing data from the client to the server (eg: POST). Thus,
+ * we can cancel the client's request timeout if the server's
+ * request timeout is set and the server has not yet sent a response.
+ */
+
+ if ((s->rep->flags & (CF_AUTO_CLOSE|CF_SHUTR)) == 0 &&
+ (tick_isset(s->req->wex) || tick_isset(s->rep->rex))) {
+ s->req->flags |= CF_READ_NOEXP;
+ s->req->rex = TICK_ETERNITY;
+ }
+
/* When any of the stream interfaces is attached to an applet,
* we have to call it here. Note that this one may wake the
* task up again. If at least one applet was called, the current
@@ -2583,6 +2599,9 @@
s->do_log(s);
}
+ /* update time stats for this session */
+ session_update_time_stats(s);
+
/* the task MUST not be in the run queue anymore */
session_free(s);
task_delete(t);
@@ -2590,6 +2609,48 @@
return NULL;
}
+/* Update the session's backend and server time stats */
+void session_update_time_stats(struct session *s)
+{
+ int t_request;
+ int t_queue;
+ int t_connect;
+ int t_data;
+ int t_close;
+ struct server *srv;
+
+ t_request = 0;
+ t_queue = s->logs.t_queue;
+ t_connect = s->logs.t_connect;
+ t_close = s->logs.t_close;
+ t_data = s->logs.t_data;
+
+ if (s->be->mode != PR_MODE_HTTP)
+ t_data = t_connect;
+
+ if (t_connect < 0 || t_data < 0)
+ return;
+
+ if (tv_isge(&s->logs.tv_request, &s->logs.tv_accept))
+ t_request = tv_ms_elapsed(&s->logs.tv_accept, &s->logs.tv_request);
+
+ t_data -= t_connect;
+ t_connect -= t_queue;
+ t_queue -= t_request;
+
+ srv = objt_server(s->target);
+ if (srv) {
+ swrate_add(&srv->counters.q_time, TIME_STATS_SAMPLES, t_queue);
+ swrate_add(&srv->counters.c_time, TIME_STATS_SAMPLES, t_connect);
+ swrate_add(&srv->counters.d_time, TIME_STATS_SAMPLES, t_data);
+ swrate_add(&srv->counters.t_time, TIME_STATS_SAMPLES, t_close);
+ }
+ swrate_add(&s->be->be_counters.q_time, TIME_STATS_SAMPLES, t_queue);
+ swrate_add(&s->be->be_counters.c_time, TIME_STATS_SAMPLES, t_connect);
+ swrate_add(&s->be->be_counters.d_time, TIME_STATS_SAMPLES, t_data);
+ swrate_add(&s->be->be_counters.t_time, TIME_STATS_SAMPLES, t_close);
+}
+
/*
* This function adjusts sess->srv_conn and maintains the previous and new
* server's served session counts. Setting newsrv to NULL is enough to release
|
[-]
[+]
|
Changed |
haproxy-1.5.3.tar.gz/src/ssl_sock.c
^
|
@@ -44,6 +44,9 @@
#include <openssl/x509.h>
#include <openssl/err.h>
#include <openssl/rand.h>
+#ifdef SSL_CTRL_SET_TLSEXT_STATUS_REQ_CB
+#include <openssl/ocsp.h>
+#endif
#include <common/buffer.h>
#include <common/compat.h>
@@ -102,6 +105,447 @@
int sslconns = 0;
int totalsslconns = 0;
+#ifndef OPENSSL_NO_DH
+static DH *local_dh_1024 = NULL;
+static DH *local_dh_2048 = NULL;
+static DH *local_dh_4096 = NULL;
+static DH *local_dh_8192 = NULL;
+#endif /* OPENSSL_NO_DH */
+
+#ifdef SSL_CTRL_SET_TLSEXT_STATUS_REQ_CB
+struct certificate_ocsp {
+ struct ebmb_node key;
+ unsigned char key_data[OCSP_MAX_CERTID_ASN1_LENGTH];
+ struct chunk response;
+ long expire;
+};
+
+/*
+ * This function returns the number of seconds elapsed
+ * since the Epoch, 1970-01-01 00:00:00 +0000 (UTC) and the
+ * date presented un ASN1_GENERALIZEDTIME.
+ *
+ * In parsing error case, it returns -1.
+ */
+static long asn1_generalizedtime_to_epoch(ASN1_GENERALIZEDTIME *d)
+{
+ long epoch;
+ char *p, *end;
+ const unsigned short month_offset[12] = {
+ 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334
+ };
+ int year, month;
+
+ if (!d || (d->type != V_ASN1_GENERALIZEDTIME)) return -1;
+
+ p = (char *)d->data;
+ end = p + d->length;
+
+ if (end - p < 4) return -1;
+ year = 1000 * (p[0] - '0') + 100 * (p[1] - '0') + 10 * (p[2] - '0') + p[3] - '0';
+ p += 4;
+ if (end - p < 2) return -1;
+ month = 10 * (p[0] - '0') + p[1] - '0';
+ if (month < 1 || month > 12) return -1;
+ /* Compute the number of seconds since 1 jan 1970 and the beginning of current month
+ We consider leap years and the current month (<marsh or not) */
+ epoch = ( ((year - 1970) * 365)
+ + ((year - (month < 3)) / 4 - (year - (month < 3)) / 100 + (year - (month < 3)) / 400)
+ - ((1970 - 1) / 4 - (1970 - 1) / 100 + (1970 - 1) / 400)
+ + month_offset[month-1]
+ ) * 24 * 60 * 60;
+ p += 2;
+ if (end - p < 2) return -1;
+ /* Add the number of seconds of completed days of current month */
+ epoch += (10 * (p[0] - '0') + p[1] - '0' - 1) * 24 * 60 * 60;
+ p += 2;
+ if (end - p < 2) return -1;
+ /* Add the completed hours of the current day */
+ epoch += (10 * (p[0] - '0') + p[1] - '0') * 60 * 60;
+ p += 2;
+ if (end - p < 2) return -1;
+ /* Add the completed minutes of the current hour */
+ epoch += (10 * (p[0] - '0') + p[1] - '0') * 60;
+ p += 2;
+ if (p == end) return -1;
+ /* Test if there is available seconds */
+ if (p[0] < '0' || p[0] > '9')
+ goto nosec;
+ if (end - p < 2) return -1;
+ /* Add the seconds of the current minute */
+ epoch += 10 * (p[0] - '0') + p[1] - '0';
+ p += 2;
+ if (p == end) return -1;
+ /* Ignore seconds float part if present */
+ if (p[0] == '.') {
+ do {
+ if (++p == end) return -1;
+ } while (p[0] >= '0' && p[0] <= '9');
+ }
+
+nosec:
+ if (p[0] == 'Z') {
+ if (end - p != 1) return -1;
+ return epoch;
+ }
+ else if (p[0] == '+') {
+ if (end - p != 5) return -1;
+ /* Apply timezone offset */
+ return epoch - ((10 * (p[1] - '0') + p[2] - '0') * 60 + (10 * (p[3] - '0') + p[4] - '0')) * 60;
+ }
+ else if (p[0] == '-') {
+ if (end - p != 5) return -1;
+ /* Apply timezone offset */
+ return epoch + ((10 * (p[1] - '0') + p[2] - '0') * 60 + (10 * (p[3] - '0') + p[4] - '0')) * 60;
+ }
+
+ return -1;
+}
+
+static struct eb_root cert_ocsp_tree = EB_ROOT_UNIQUE;
+
+/* This function starts to check if the OCSP response (in DER format) contained
+ * in chunk 'ocsp_response' is valid (else exits on error).
+ * If 'cid' is not NULL, it will be compared to the OCSP certificate ID
+ * contained in the OCSP Response and exits on error if no match.
+ * If it's a valid OCSP Response:
+ * If 'ocsp' is not NULL, the chunk is copied in the OCSP response's container
+ * pointed by 'ocsp'.
+ * If 'ocsp' is NULL, the function looks up into the OCSP response's
+ * containers tree (using as index the ASN1 form of the OCSP Certificate ID extracted
+ * from the response) and exits on error if not found. Finally, If an OCSP response is
+ * already present in the container, it will be overwritten.
+ *
+ * Note: OCSP response containing more than one OCSP Single response is not
+ * considered valid.
+ *
+ * Returns 0 on success, 1 in error case.
+ */
+static int ssl_sock_load_ocsp_response(struct chunk *ocsp_response, struct certificate_ocsp *ocsp, OCSP_CERTID *cid, char **err)
+{
+ OCSP_RESPONSE *resp;
+ OCSP_BASICRESP *bs = NULL;
+ OCSP_SINGLERESP *sr;
+ unsigned char *p = (unsigned char *)ocsp_response->str;
+ int rc , count_sr;
+ ASN1_GENERALIZEDTIME *revtime, *thisupd, *nextupd = NULL;
+ int reason;
+ int ret = 1;
+
+ resp = d2i_OCSP_RESPONSE(NULL, (const unsigned char **)&p, ocsp_response->len);
+ if (!resp) {
+ memprintf(err, "Unable to parse OCSP response");
+ goto out;
+ }
+
+ rc = OCSP_response_status(resp);
+ if (rc != OCSP_RESPONSE_STATUS_SUCCESSFUL) {
+ memprintf(err, "OCSP response status not successful");
+ goto out;
+ }
+
+ bs = OCSP_response_get1_basic(resp);
+ if (!bs) {
+ memprintf(err, "Failed to get basic response from OCSP Response");
+ goto out;
+ }
+
+ count_sr = OCSP_resp_count(bs);
+ if (count_sr > 1) {
+ memprintf(err, "OCSP response ignored because contains multiple single responses (%d)", count_sr);
+ goto out;
+ }
+
+ sr = OCSP_resp_get0(bs, 0);
+ if (!sr) {
+ memprintf(err, "Failed to get OCSP single response");
+ goto out;
+ }
+
+ rc = OCSP_single_get0_status(sr, &reason, &revtime, &thisupd, &nextupd);
+ if (rc != V_OCSP_CERTSTATUS_GOOD) {
+ memprintf(err, "OCSP single response: certificate status not good");
+ goto out;
+ }
+
+ if (!nextupd) {
+ memprintf(err, "OCSP single response: missing nextupdate");
+ goto out;
+ }
+
+ rc = OCSP_check_validity(thisupd, nextupd, OCSP_MAX_RESPONSE_TIME_SKEW, -1);
+ if (!rc) {
+ memprintf(err, "OCSP single response: no longer valid.");
+ goto out;
+ }
+
+ if (cid) {
+ if (OCSP_id_cmp(sr->certId, cid)) {
+ memprintf(err, "OCSP single response: Certificate ID does not match certificate and issuer");
+ goto out;
+ }
+ }
+
+ if (!ocsp) {
+ unsigned char key[OCSP_MAX_CERTID_ASN1_LENGTH];
+ unsigned char *p;
+
+ rc = i2d_OCSP_CERTID(sr->certId, NULL);
+ if (!rc) {
+ memprintf(err, "OCSP single response: Unable to encode Certificate ID");
+ goto out;
+ }
+
+ if (rc > OCSP_MAX_CERTID_ASN1_LENGTH) {
+ memprintf(err, "OCSP single response: Certificate ID too long");
+ goto out;
+ }
+
+ p = key;
+ memset(key, 0, OCSP_MAX_CERTID_ASN1_LENGTH);
+ i2d_OCSP_CERTID(sr->certId, &p);
+ ocsp = (struct certificate_ocsp *)ebmb_lookup(&cert_ocsp_tree, key, OCSP_MAX_CERTID_ASN1_LENGTH);
+ if (!ocsp) {
+ memprintf(err, "OCSP single response: Certificate ID does not match any certificate or issuer");
+ goto out;
+ }
+ }
+
+ /* According to comments on "chunk_dup", the
+ previous chunk buffer will be freed */
+ if (!chunk_dup(&ocsp->response, ocsp_response)) {
+ memprintf(err, "OCSP response: Memory allocation error");
+ goto out;
+ }
+
+ ocsp->expire = asn1_generalizedtime_to_epoch(nextupd) - OCSP_MAX_RESPONSE_TIME_SKEW;
+
+ ret = 0;
+out:
+ if (bs)
+ OCSP_BASICRESP_free(bs);
+
+ if (resp)
+ OCSP_RESPONSE_free(resp);
+
+ return ret;
+}
+/*
+ * External function use to update the OCSP response in the OCSP response's
+ * containers tree. The chunk 'ocsp_response' must contain the OCSP response
+ * to update in DER format.
+ *
+ * Returns 0 on success, 1 in error case.
+ */
+int ssl_sock_update_ocsp_response(struct chunk *ocsp_response, char **err)
+{
+ return ssl_sock_load_ocsp_response(ocsp_response, NULL, NULL, err);
+}
+
+/*
+ * This function load the OCSP Resonse in DER format contained in file at
+ * path 'ocsp_path' and call 'ssl_sock_load_ocsp_response'
+ *
+ * Returns 0 on success, 1 in error case.
+ */
+static int ssl_sock_load_ocsp_response_from_file(const char *ocsp_path, struct certificate_ocsp *ocsp, OCSP_CERTID *cid, char **err)
+{
+ int fd = -1;
+ int r = 0;
+ int ret = 1;
+
+ fd = open(ocsp_path, O_RDONLY);
+ if (fd == -1) {
+ memprintf(err, "Error opening OCSP response file");
+ goto end;
+ }
+
+ trash.len = 0;
+ while (trash.len < trash.size) {
+ r = read(fd, trash.str + trash.len, trash.size - trash.len);
+ if (r < 0) {
+ if (errno == EINTR)
+ continue;
+
+ memprintf(err, "Error reading OCSP response from file");
+ goto end;
+ }
+ else if (r == 0) {
+ break;
+ }
+ trash.len += r;
+ }
+
+ close(fd);
+ fd = -1;
+
+ ret = ssl_sock_load_ocsp_response(&trash, ocsp, cid, err);
+end:
+ if (fd != -1)
+ close(fd);
+
+ return ret;
+}
+
+/*
+ * Callback used to set OCSP status extension content in server hello.
+ */
+int ssl_sock_ocsp_stapling_cbk(SSL *ssl, void *arg)
+{
+ struct certificate_ocsp *ocsp = (struct certificate_ocsp *)arg;
+ char* ssl_buf;
+
+ if (!ocsp ||
+ !ocsp->response.str ||
+ !ocsp->response.len ||
+ (ocsp->expire < now.tv_sec))
+ return SSL_TLSEXT_ERR_NOACK;
+
+ ssl_buf = OPENSSL_malloc(ocsp->response.len);
+ if (!ssl_buf)
+ return SSL_TLSEXT_ERR_NOACK;
+
+ memcpy(ssl_buf, ocsp->response.str, ocsp->response.len);
+ SSL_set_tlsext_status_ocsp_resp(ssl, ssl_buf, ocsp->response.len);
+
+ return SSL_TLSEXT_ERR_OK;
+}
+
+/*
+ * This function enables the handling of OCSP status extension on 'ctx' if a
+ * file name 'cert_path' suffixed using ".ocsp" is present.
+ * To enable OCSP status extension, the issuer's certificate is mandatory.
+ * It should be present in the certificate's extra chain builded from file
+ * 'cert_path'. If not found, the issuer certificate is loaded from a file
+ * named 'cert_path' suffixed using '.issuer'.
+ *
+ * In addition, ".ocsp" file content is loaded as a DER format of an OCSP
+ * response. If file is empty or content is not a valid OCSP response,
+ * OCSP status extension is enabled but OCSP response is ignored (a warning
+ * is displayed).
+ *
+ * Returns 1 if no ".ocsp" file found, 0 if OCSP status extension is
+ * succesfully enabled, or -1 in other error case.
+ */
+static int ssl_sock_load_ocsp(SSL_CTX *ctx, const char *cert_path)
+{
+
+ BIO *in = NULL;
+ X509 *x, *xi = NULL, *issuer = NULL;
+ STACK_OF(X509) *chain = NULL;
+ OCSP_CERTID *cid = NULL;
+ SSL *ssl;
+ char ocsp_path[MAXPATHLEN+1];
+ int i, ret = -1;
+ struct stat st;
+ struct certificate_ocsp *ocsp = NULL, *iocsp;
+ char *warn = NULL;
+ unsigned char *p;
+
+ snprintf(ocsp_path, MAXPATHLEN+1, "%s.ocsp", cert_path);
+
+ if (stat(ocsp_path, &st))
+ return 1;
+
+ ssl = SSL_new(ctx);
+ if (!ssl)
+ goto out;
+
+ x = SSL_get_certificate(ssl);
+ if (!x)
+ goto out;
+
+ /* Try to lookup for issuer in certificate extra chain */
+#ifdef SSL_CTRL_GET_EXTRA_CHAIN_CERTS
+ SSL_CTX_get_extra_chain_certs(ctx, &chain);
+#else
+ chain = ctx->extra_certs;
+#endif
+ for (i = 0; i < sk_X509_num(chain); i++) {
+ issuer = sk_X509_value(chain, i);
+ if (X509_check_issued(issuer, x) == X509_V_OK)
+ break;
+ else
+ issuer = NULL;
+ }
+
+ /* If not found try to load issuer from a suffixed file */
+ if (!issuer) {
+ char issuer_path[MAXPATHLEN+1];
+
+ in = BIO_new(BIO_s_file());
+ if (!in)
+ goto out;
+
+ snprintf(issuer_path, MAXPATHLEN+1, "%s.issuer", cert_path);
+ if (BIO_read_filename(in, issuer_path) <= 0)
+ goto out;
+
+ xi = PEM_read_bio_X509_AUX(in, NULL, ctx->default_passwd_callback, ctx->default_passwd_callback_userdata);
+ if (!xi)
+ goto out;
+
+ if (X509_check_issued(xi, x) != X509_V_OK)
+ goto out;
+
+ issuer = xi;
+ }
+
+ cid = OCSP_cert_to_id(0, x, issuer);
+ if (!cid)
+ goto out;
+
+ i = i2d_OCSP_CERTID(cid, NULL);
+ if (!i || (i > OCSP_MAX_CERTID_ASN1_LENGTH))
+ goto out;
+
+ ocsp = calloc(1, sizeof(struct certificate_ocsp));
+ if (!ocsp)
+ goto out;
+
+ p = ocsp->key_data;
+ i2d_OCSP_CERTID(cid, &p);
+
+ iocsp = (struct certificate_ocsp *)ebmb_insert(&cert_ocsp_tree, &ocsp->key, OCSP_MAX_CERTID_ASN1_LENGTH);
+ if (iocsp == ocsp)
+ ocsp = NULL;
+
+ SSL_CTX_set_tlsext_status_cb(ctx, ssl_sock_ocsp_stapling_cbk);
+ SSL_CTX_set_tlsext_status_arg(ctx, iocsp);
+
+ ret = 0;
+
+ warn = NULL;
+ if (ssl_sock_load_ocsp_response_from_file(ocsp_path, iocsp, cid, &warn)) {
+ memprintf(&warn, "Loading '%s': %s. Content will be ignored", ocsp_path, warn ? warn : "failure");
+ Warning("%s.\n", warn);
+ }
+
+out:
+ if (ssl)
+ SSL_free(ssl);
+
+ if (in)
+ BIO_free(in);
+
+ if (xi)
+ X509_free(xi);
+
+ if (cid)
+ OCSP_CERTID_free(cid);
+
+ if (ocsp)
+ free(ocsp);
+
+ if (warn)
+ free(warn);
+
+
+ return ret;
+}
+
+#endif
+
void ssl_sock_infocbk(const SSL *ssl, int where, int ret)
{
struct connection *conn = (struct connection *)SSL_get_app_data(ssl);
@@ -314,6 +758,304 @@
#endif /* SSL_CTRL_SET_TLSEXT_HOSTNAME */
#ifndef OPENSSL_NO_DH
+
+static DH * ssl_get_dh_1024(void)
+{
+#if OPENSSL_VERSION_NUMBER < 0x0090801fL
+ static const unsigned char rfc_2409_prime_1024[] = {
+ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xC9,0x0F,0xDA,0xA2,
+ 0x21,0x68,0xC2,0x34,0xC4,0xC6,0x62,0x8B,0x80,0xDC,0x1C,0xD1,
+ 0x29,0x02,0x4E,0x08,0x8A,0x67,0xCC,0x74,0x02,0x0B,0xBE,0xA6,
+ 0x3B,0x13,0x9B,0x22,0x51,0x4A,0x08,0x79,0x8E,0x34,0x04,0xDD,
+ 0xEF,0x95,0x19,0xB3,0xCD,0x3A,0x43,0x1B,0x30,0x2B,0x0A,0x6D,
+ 0xF2,0x5F,0x14,0x37,0x4F,0xE1,0x35,0x6D,0x6D,0x51,0xC2,0x45,
+ 0xE4,0x85,0xB5,0x76,0x62,0x5E,0x7E,0xC6,0xF4,0x4C,0x42,0xE9,
+ 0xA6,0x37,0xED,0x6B,0x0B,0xFF,0x5C,0xB6,0xF4,0x06,0xB7,0xED,
+ 0xEE,0x38,0x6B,0xFB,0x5A,0x89,0x9F,0xA5,0xAE,0x9F,0x24,0x11,
+ 0x7C,0x4B,0x1F,0xE6,0x49,0x28,0x66,0x51,0xEC,0xE6,0x53,0x81,
+ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
+ };
+#endif
+ DH *dh = DH_new();
+ if (dh) {
+#if OPENSSL_VERSION_NUMBER >= 0x0090801fL
+ dh->p = get_rfc2409_prime_1024(NULL);
+#else
+ dh->p = BN_bin2bn(rfc_2409_prime_1024, sizeof rfc_2409_prime_1024, NULL);
+#endif
+ /* See RFC 2409, Section 6 "Oakley Groups"
+ for the reason why 2 is used as generator.
+ */
+ BN_dec2bn(&dh->g, "2");
+ if (!dh->p || !dh->g) {
+ DH_free(dh);
+ dh = NULL;
+ }
+ }
+ return dh;
+}
+
+static DH *ssl_get_dh_2048(void)
+{
+#if OPENSSL_VERSION_NUMBER < 0x0090801fL
+ static const unsigned char rfc_3526_prime_2048[] = {
+ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xC9,0x0F,0xDA,0xA2,
+ 0x21,0x68,0xC2,0x34,0xC4,0xC6,0x62,0x8B,0x80,0xDC,0x1C,0xD1,
+ 0x29,0x02,0x4E,0x08,0x8A,0x67,0xCC,0x74,0x02,0x0B,0xBE,0xA6,
+ 0x3B,0x13,0x9B,0x22,0x51,0x4A,0x08,0x79,0x8E,0x34,0x04,0xDD,
+ 0xEF,0x95,0x19,0xB3,0xCD,0x3A,0x43,0x1B,0x30,0x2B,0x0A,0x6D,
+ 0xF2,0x5F,0x14,0x37,0x4F,0xE1,0x35,0x6D,0x6D,0x51,0xC2,0x45,
+ 0xE4,0x85,0xB5,0x76,0x62,0x5E,0x7E,0xC6,0xF4,0x4C,0x42,0xE9,
+ 0xA6,0x37,0xED,0x6B,0x0B,0xFF,0x5C,0xB6,0xF4,0x06,0xB7,0xED,
+ 0xEE,0x38,0x6B,0xFB,0x5A,0x89,0x9F,0xA5,0xAE,0x9F,0x24,0x11,
+ 0x7C,0x4B,0x1F,0xE6,0x49,0x28,0x66,0x51,0xEC,0xE4,0x5B,0x3D,
+ 0xC2,0x00,0x7C,0xB8,0xA1,0x63,0xBF,0x05,0x98,0xDA,0x48,0x36,
+ 0x1C,0x55,0xD3,0x9A,0x69,0x16,0x3F,0xA8,0xFD,0x24,0xCF,0x5F,
+ 0x83,0x65,0x5D,0x23,0xDC,0xA3,0xAD,0x96,0x1C,0x62,0xF3,0x56,
+ 0x20,0x85,0x52,0xBB,0x9E,0xD5,0x29,0x07,0x70,0x96,0x96,0x6D,
+ 0x67,0x0C,0x35,0x4E,0x4A,0xBC,0x98,0x04,0xF1,0x74,0x6C,0x08,
+ 0xCA,0x18,0x21,0x7C,0x32,0x90,0x5E,0x46,0x2E,0x36,0xCE,0x3B,
+ 0xE3,0x9E,0x77,0x2C,0x18,0x0E,0x86,0x03,0x9B,0x27,0x83,0xA2,
+ 0xEC,0x07,0xA2,0x8F,0xB5,0xC5,0x5D,0xF0,0x6F,0x4C,0x52,0xC9,
+ 0xDE,0x2B,0xCB,0xF6,0x95,0x58,0x17,0x18,0x39,0x95,0x49,0x7C,
+ 0xEA,0x95,0x6A,0xE5,0x15,0xD2,0x26,0x18,0x98,0xFA,0x05,0x10,
+ 0x15,0x72,0x8E,0x5A,0x8A,0xAC,0xAA,0x68,0xFF,0xFF,0xFF,0xFF,
+ 0xFF,0xFF,0xFF,0xFF,
+ };
+#endif
+ DH *dh = DH_new();
+ if (dh) {
+#if OPENSSL_VERSION_NUMBER >= 0x0090801fL
+ dh->p = get_rfc3526_prime_2048(NULL);
+#else
+ dh->p = BN_bin2bn(rfc_3526_prime_2048, sizeof rfc_3526_prime_2048, NULL);
+#endif
+ /* See RFC 3526, Section 3 "2048-bit MODP Group"
+ for the reason why 2 is used as generator.
+ */
+ BN_dec2bn(&dh->g, "2");
+ if (!dh->p || !dh->g) {
+ DH_free(dh);
+ dh = NULL;
+ }
+ }
+ return dh;
+}
+
+static DH *ssl_get_dh_4096(void)
+{
+#if OPENSSL_VERSION_NUMBER < 0x0090801fL
+ static const unsigned char rfc_3526_prime_4096[] = {
+ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xC9,0x0F,0xDA,0xA2,
+ 0x21,0x68,0xC2,0x34,0xC4,0xC6,0x62,0x8B,0x80,0xDC,0x1C,0xD1,
+ 0x29,0x02,0x4E,0x08,0x8A,0x67,0xCC,0x74,0x02,0x0B,0xBE,0xA6,
+ 0x3B,0x13,0x9B,0x22,0x51,0x4A,0x08,0x79,0x8E,0x34,0x04,0xDD,
+ 0xEF,0x95,0x19,0xB3,0xCD,0x3A,0x43,0x1B,0x30,0x2B,0x0A,0x6D,
+ 0xF2,0x5F,0x14,0x37,0x4F,0xE1,0x35,0x6D,0x6D,0x51,0xC2,0x45,
+ 0xE4,0x85,0xB5,0x76,0x62,0x5E,0x7E,0xC6,0xF4,0x4C,0x42,0xE9,
+ 0xA6,0x37,0xED,0x6B,0x0B,0xFF,0x5C,0xB6,0xF4,0x06,0xB7,0xED,
+ 0xEE,0x38,0x6B,0xFB,0x5A,0x89,0x9F,0xA5,0xAE,0x9F,0x24,0x11,
+ 0x7C,0x4B,0x1F,0xE6,0x49,0x28,0x66,0x51,0xEC,0xE4,0x5B,0x3D,
+ 0xC2,0x00,0x7C,0xB8,0xA1,0x63,0xBF,0x05,0x98,0xDA,0x48,0x36,
+ 0x1C,0x55,0xD3,0x9A,0x69,0x16,0x3F,0xA8,0xFD,0x24,0xCF,0x5F,
+ 0x83,0x65,0x5D,0x23,0xDC,0xA3,0xAD,0x96,0x1C,0x62,0xF3,0x56,
+ 0x20,0x85,0x52,0xBB,0x9E,0xD5,0x29,0x07,0x70,0x96,0x96,0x6D,
+ 0x67,0x0C,0x35,0x4E,0x4A,0xBC,0x98,0x04,0xF1,0x74,0x6C,0x08,
+ 0xCA,0x18,0x21,0x7C,0x32,0x90,0x5E,0x46,0x2E,0x36,0xCE,0x3B,
+ 0xE3,0x9E,0x77,0x2C,0x18,0x0E,0x86,0x03,0x9B,0x27,0x83,0xA2,
+ 0xEC,0x07,0xA2,0x8F,0xB5,0xC5,0x5D,0xF0,0x6F,0x4C,0x52,0xC9,
+ 0xDE,0x2B,0xCB,0xF6,0x95,0x58,0x17,0x18,0x39,0x95,0x49,0x7C,
+ 0xEA,0x95,0x6A,0xE5,0x15,0xD2,0x26,0x18,0x98,0xFA,0x05,0x10,
+ 0x15,0x72,0x8E,0x5A,0x8A,0xAA,0xC4,0x2D,0xAD,0x33,0x17,0x0D,
+ 0x04,0x50,0x7A,0x33,0xA8,0x55,0x21,0xAB,0xDF,0x1C,0xBA,0x64,
+ 0xEC,0xFB,0x85,0x04,0x58,0xDB,0xEF,0x0A,0x8A,0xEA,0x71,0x57,
+ 0x5D,0x06,0x0C,0x7D,0xB3,0x97,0x0F,0x85,0xA6,0xE1,0xE4,0xC7,
+ 0xAB,0xF5,0xAE,0x8C,0xDB,0x09,0x33,0xD7,0x1E,0x8C,0x94,0xE0,
+ 0x4A,0x25,0x61,0x9D,0xCE,0xE3,0xD2,0x26,0x1A,0xD2,0xEE,0x6B,
+ 0xF1,0x2F,0xFA,0x06,0xD9,0x8A,0x08,0x64,0xD8,0x76,0x02,0x73,
+ 0x3E,0xC8,0x6A,0x64,0x52,0x1F,0x2B,0x18,0x17,0x7B,0x20,0x0C,
+ 0xBB,0xE1,0x17,0x57,0x7A,0x61,0x5D,0x6C,0x77,0x09,0x88,0xC0,
+ 0xBA,0xD9,0x46,0xE2,0x08,0xE2,0x4F,0xA0,0x74,0xE5,0xAB,0x31,
+ 0x43,0xDB,0x5B,0xFC,0xE0,0xFD,0x10,0x8E,0x4B,0x82,0xD1,0x20,
+ 0xA9,0x21,0x08,0x01,0x1A,0x72,0x3C,0x12,0xA7,0x87,0xE6,0xD7,
+ 0x88,0x71,0x9A,0x10,0xBD,0xBA,0x5B,0x26,0x99,0xC3,0x27,0x18,
+ 0x6A,0xF4,0xE2,0x3C,0x1A,0x94,0x68,0x34,0xB6,0x15,0x0B,0xDA,
+ 0x25,0x83,0xE9,0xCA,0x2A,0xD4,0x4C,0xE8,0xDB,0xBB,0xC2,0xDB,
+ 0x04,0xDE,0x8E,0xF9,0x2E,0x8E,0xFC,0x14,0x1F,0xBE,0xCA,0xA6,
+ 0x28,0x7C,0x59,0x47,0x4E,0x6B,0xC0,0x5D,0x99,0xB2,0x96,0x4F,
+ 0xA0,0x90,0xC3,0xA2,0x23,0x3B,0xA1,0x86,0x51,0x5B,0xE7,0xED,
+ 0x1F,0x61,0x29,0x70,0xCE,0xE2,0xD7,0xAF,0xB8,0x1B,0xDD,0x76,
+ 0x21,0x70,0x48,0x1C,0xD0,0x06,0x91,0x27,0xD5,0xB0,0x5A,0xA9,
+ 0x93,0xB4,0xEA,0x98,0x8D,0x8F,0xDD,0xC1,0x86,0xFF,0xB7,0xDC,
+ 0x90,0xA6,0xC0,0x8F,0x4D,0xF4,0x35,0xC9,0x34,0x06,0x31,0x99,
+ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
+ };
+#endif
+ DH *dh = DH_new();
+ if (dh) {
+#if OPENSSL_VERSION_NUMBER >= 0x0090801fL
+ dh->p = get_rfc3526_prime_4096(NULL);
+#else
+ dh->p = BN_bin2bn(rfc_3526_prime_4096, sizeof rfc_3526_prime_4096, NULL);
+#endif
+ /* See RFC 3526, Section 5 "4096-bit MODP Group"
+ for the reason why 2 is used as generator.
+ */
+ BN_dec2bn(&dh->g, "2");
+ if (!dh->p || !dh->g) {
+ DH_free(dh);
+ dh = NULL;
+ }
+ }
+ return dh;
+}
+
+static DH *ssl_get_dh_8192(void)
+{
+#if OPENSSL_VERSION_NUMBER < 0x0090801fL
+ static const unsigned char rfc_3526_prime_8192[] = {
+ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xC9,0x0F,0xDA,0xA2,
+ 0x21,0x68,0xC2,0x34,0xC4,0xC6,0x62,0x8B,0x80,0xDC,0x1C,0xD1,
+ 0x29,0x02,0x4E,0x08,0x8A,0x67,0xCC,0x74,0x02,0x0B,0xBE,0xA6,
+ 0x3B,0x13,0x9B,0x22,0x51,0x4A,0x08,0x79,0x8E,0x34,0x04,0xDD,
+ 0xEF,0x95,0x19,0xB3,0xCD,0x3A,0x43,0x1B,0x30,0x2B,0x0A,0x6D,
+ 0xF2,0x5F,0x14,0x37,0x4F,0xE1,0x35,0x6D,0x6D,0x51,0xC2,0x45,
+ 0xE4,0x85,0xB5,0x76,0x62,0x5E,0x7E,0xC6,0xF4,0x4C,0x42,0xE9,
+ 0xA6,0x37,0xED,0x6B,0x0B,0xFF,0x5C,0xB6,0xF4,0x06,0xB7,0xED,
+ 0xEE,0x38,0x6B,0xFB,0x5A,0x89,0x9F,0xA5,0xAE,0x9F,0x24,0x11,
+ 0x7C,0x4B,0x1F,0xE6,0x49,0x28,0x66,0x51,0xEC,0xE4,0x5B,0x3D,
+ 0xC2,0x00,0x7C,0xB8,0xA1,0x63,0xBF,0x05,0x98,0xDA,0x48,0x36,
+ 0x1C,0x55,0xD3,0x9A,0x69,0x16,0x3F,0xA8,0xFD,0x24,0xCF,0x5F,
+ 0x83,0x65,0x5D,0x23,0xDC,0xA3,0xAD,0x96,0x1C,0x62,0xF3,0x56,
+ 0x20,0x85,0x52,0xBB,0x9E,0xD5,0x29,0x07,0x70,0x96,0x96,0x6D,
+ 0x67,0x0C,0x35,0x4E,0x4A,0xBC,0x98,0x04,0xF1,0x74,0x6C,0x08,
+ 0xCA,0x18,0x21,0x7C,0x32,0x90,0x5E,0x46,0x2E,0x36,0xCE,0x3B,
+ 0xE3,0x9E,0x77,0x2C,0x18,0x0E,0x86,0x03,0x9B,0x27,0x83,0xA2,
+ 0xEC,0x07,0xA2,0x8F,0xB5,0xC5,0x5D,0xF0,0x6F,0x4C,0x52,0xC9,
+ 0xDE,0x2B,0xCB,0xF6,0x95,0x58,0x17,0x18,0x39,0x95,0x49,0x7C,
+ 0xEA,0x95,0x6A,0xE5,0x15,0xD2,0x26,0x18,0x98,0xFA,0x05,0x10,
+ 0x15,0x72,0x8E,0x5A,0x8A,0xAA,0xC4,0x2D,0xAD,0x33,0x17,0x0D,
+ 0x04,0x50,0x7A,0x33,0xA8,0x55,0x21,0xAB,0xDF,0x1C,0xBA,0x64,
+ 0xEC,0xFB,0x85,0x04,0x58,0xDB,0xEF,0x0A,0x8A,0xEA,0x71,0x57,
+ 0x5D,0x06,0x0C,0x7D,0xB3,0x97,0x0F,0x85,0xA6,0xE1,0xE4,0xC7,
+ 0xAB,0xF5,0xAE,0x8C,0xDB,0x09,0x33,0xD7,0x1E,0x8C,0x94,0xE0,
+ 0x4A,0x25,0x61,0x9D,0xCE,0xE3,0xD2,0x26,0x1A,0xD2,0xEE,0x6B,
+ 0xF1,0x2F,0xFA,0x06,0xD9,0x8A,0x08,0x64,0xD8,0x76,0x02,0x73,
+ 0x3E,0xC8,0x6A,0x64,0x52,0x1F,0x2B,0x18,0x17,0x7B,0x20,0x0C,
+ 0xBB,0xE1,0x17,0x57,0x7A,0x61,0x5D,0x6C,0x77,0x09,0x88,0xC0,
+ 0xBA,0xD9,0x46,0xE2,0x08,0xE2,0x4F,0xA0,0x74,0xE5,0xAB,0x31,
+ 0x43,0xDB,0x5B,0xFC,0xE0,0xFD,0x10,0x8E,0x4B,0x82,0xD1,0x20,
+ 0xA9,0x21,0x08,0x01,0x1A,0x72,0x3C,0x12,0xA7,0x87,0xE6,0xD7,
+ 0x88,0x71,0x9A,0x10,0xBD,0xBA,0x5B,0x26,0x99,0xC3,0x27,0x18,
+ 0x6A,0xF4,0xE2,0x3C,0x1A,0x94,0x68,0x34,0xB6,0x15,0x0B,0xDA,
+ 0x25,0x83,0xE9,0xCA,0x2A,0xD4,0x4C,0xE8,0xDB,0xBB,0xC2,0xDB,
+ 0x04,0xDE,0x8E,0xF9,0x2E,0x8E,0xFC,0x14,0x1F,0xBE,0xCA,0xA6,
+ 0x28,0x7C,0x59,0x47,0x4E,0x6B,0xC0,0x5D,0x99,0xB2,0x96,0x4F,
+ 0xA0,0x90,0xC3,0xA2,0x23,0x3B,0xA1,0x86,0x51,0x5B,0xE7,0xED,
+ 0x1F,0x61,0x29,0x70,0xCE,0xE2,0xD7,0xAF,0xB8,0x1B,0xDD,0x76,
+ 0x21,0x70,0x48,0x1C,0xD0,0x06,0x91,0x27,0xD5,0xB0,0x5A,0xA9,
+ 0x93,0xB4,0xEA,0x98,0x8D,0x8F,0xDD,0xC1,0x86,0xFF,0xB7,0xDC,
+ 0x90,0xA6,0xC0,0x8F,0x4D,0xF4,0x35,0xC9,0x34,0x02,0x84,0x92,
+ 0x36,0xC3,0xFA,0xB4,0xD2,0x7C,0x70,0x26,0xC1,0xD4,0xDC,0xB2,
+ 0x60,0x26,0x46,0xDE,0xC9,0x75,0x1E,0x76,0x3D,0xBA,0x37,0xBD,
+ 0xF8,0xFF,0x94,0x06,0xAD,0x9E,0x53,0x0E,0xE5,0xDB,0x38,0x2F,
+ 0x41,0x30,0x01,0xAE,0xB0,0x6A,0x53,0xED,0x90,0x27,0xD8,0x31,
+ 0x17,0x97,0x27,0xB0,0x86,0x5A,0x89,0x18,0xDA,0x3E,0xDB,0xEB,
+ 0xCF,0x9B,0x14,0xED,0x44,0xCE,0x6C,0xBA,0xCE,0xD4,0xBB,0x1B,
+ 0xDB,0x7F,0x14,0x47,0xE6,0xCC,0x25,0x4B,0x33,0x20,0x51,0x51,
+ 0x2B,0xD7,0xAF,0x42,0x6F,0xB8,0xF4,0x01,0x37,0x8C,0xD2,0xBF,
+ 0x59,0x83,0xCA,0x01,0xC6,0x4B,0x92,0xEC,0xF0,0x32,0xEA,0x15,
+ 0xD1,0x72,0x1D,0x03,0xF4,0x82,0xD7,0xCE,0x6E,0x74,0xFE,0xF6,
+ 0xD5,0x5E,0x70,0x2F,0x46,0x98,0x0C,0x82,0xB5,0xA8,0x40,0x31,
+ 0x90,0x0B,0x1C,0x9E,0x59,0xE7,0xC9,0x7F,0xBE,0xC7,0xE8,0xF3,
+ 0x23,0xA9,0x7A,0x7E,0x36,0xCC,0x88,0xBE,0x0F,0x1D,0x45,0xB7,
+ 0xFF,0x58,0x5A,0xC5,0x4B,0xD4,0x07,0xB2,0x2B,0x41,0x54,0xAA,
+ 0xCC,0x8F,0x6D,0x7E,0xBF,0x48,0xE1,0xD8,0x14,0xCC,0x5E,0xD2,
+ 0x0F,0x80,0x37,0xE0,0xA7,0x97,0x15,0xEE,0xF2,0x9B,0xE3,0x28,
+ 0x06,0xA1,0xD5,0x8B,0xB7,0xC5,0xDA,0x76,0xF5,0x50,0xAA,0x3D,
+ 0x8A,0x1F,0xBF,0xF0,0xEB,0x19,0xCC,0xB1,0xA3,0x13,0xD5,0x5C,
+ 0xDA,0x56,0xC9,0xEC,0x2E,0xF2,0x96,0x32,0x38,0x7F,0xE8,0xD7,
+ 0x6E,0x3C,0x04,0x68,0x04,0x3E,0x8F,0x66,0x3F,0x48,0x60,0xEE,
+ 0x12,0xBF,0x2D,0x5B,0x0B,0x74,0x74,0xD6,0xE6,0x94,0xF9,0x1E,
+ 0x6D,0xBE,0x11,0x59,0x74,0xA3,0x92,0x6F,0x12,0xFE,0xE5,0xE4,
+ 0x38,0x77,0x7C,0xB6,0xA9,0x32,0xDF,0x8C,0xD8,0xBE,0xC4,0xD0,
+ 0x73,0xB9,0x31,0xBA,0x3B,0xC8,0x32,0xB6,0x8D,0x9D,0xD3,0x00,
+ 0x74,0x1F,0xA7,0xBF,0x8A,0xFC,0x47,0xED,0x25,0x76,0xF6,0x93,
+ 0x6B,0xA4,0x24,0x66,0x3A,0xAB,0x63,0x9C,0x5A,0xE4,0xF5,0x68,
+ 0x34,0x23,0xB4,0x74,0x2B,0xF1,0xC9,0x78,0x23,0x8F,0x16,0xCB,
+ 0xE3,0x9D,0x65,0x2D,0xE3,0xFD,0xB8,0xBE,0xFC,0x84,0x8A,0xD9,
+ 0x22,0x22,0x2E,0x04,0xA4,0x03,0x7C,0x07,0x13,0xEB,0x57,0xA8,
+ 0x1A,0x23,0xF0,0xC7,0x34,0x73,0xFC,0x64,0x6C,0xEA,0x30,0x6B,
+ 0x4B,0xCB,0xC8,0x86,0x2F,0x83,0x85,0xDD,0xFA,0x9D,0x4B,0x7F,
+ 0xA2,0xC0,0x87,0xE8,0x79,0x68,0x33,0x03,0xED,0x5B,0xDD,0x3A,
+ 0x06,0x2B,0x3C,0xF5,0xB3,0xA2,0x78,0xA6,0x6D,0x2A,0x13,0xF8,
+ 0x3F,0x44,0xF8,0x2D,0xDF,0x31,0x0E,0xE0,0x74,0xAB,0x6A,0x36,
+ 0x45,0x97,0xE8,0x99,0xA0,0x25,0x5D,0xC1,0x64,0xF3,0x1C,0xC5,
+ 0x08,0x46,0x85,0x1D,0xF9,0xAB,0x48,0x19,0x5D,0xED,0x7E,0xA1,
+ 0xB1,0xD5,0x10,0xBD,0x7E,0xE7,0x4D,0x73,0xFA,0xF3,0x6B,0xC3,
+ 0x1E,0xCF,0xA2,0x68,0x35,0x90,0x46,0xF4,0xEB,0x87,0x9F,0x92,
+ 0x40,0x09,0x43,0x8B,0x48,0x1C,0x6C,0xD7,0x88,0x9A,0x00,0x2E,
+ 0xD5,0xEE,0x38,0x2B,0xC9,0x19,0x0D,0xA6,0xFC,0x02,0x6E,0x47,
+ 0x95,0x58,0xE4,0x47,0x56,0x77,0xE9,0xAA,0x9E,0x30,0x50,0xE2,
+ 0x76,0x56,0x94,0xDF,0xC8,0x1F,0x56,0xE8,0x80,0xB9,0x6E,0x71,
+ 0x60,0xC9,0x80,0xDD,0x98,0xED,0xD3,0xDF,0xFF,0xFF,0xFF,0xFF,
+ 0xFF,0xFF,0xFF,0xFF,
+ };
+#endif
+ DH *dh = DH_new();
+ if (dh) {
+#if OPENSSL_VERSION_NUMBER >= 0x0090801fL
+ dh->p = get_rfc3526_prime_8192(NULL);
+#else
+ dh->p = BN_bin2bn(rfc_3526_prime_8192, sizeof rfc_3526_prime_8192, NULL);
+#endif
+ /* See RFC 3526, Section 7 "8192-bit MODP Group"
+ for the reason why 2 is used as generator.
+ */
+ BN_dec2bn(&dh->g, "2");
+ if (!dh->p || !dh->g) {
+ DH_free(dh);
+ dh = NULL;
+ }
+ }
+ return dh;
+}
+
+/* Returns Diffie-Hellman parameters matching the private key length
+ but not exceeding global.tune.ssl_default_dh_param */
+static DH *ssl_get_tmp_dh(SSL *ssl, int export, int keylen)
+{
+ DH *dh = NULL;
+ EVP_PKEY *pkey = SSL_get_privatekey(ssl);
+ int type = pkey ? EVP_PKEY_type(pkey->type) : EVP_PKEY_NONE;
+
+ /* The keylen supplied by OpenSSL can only be 512 or 1024.
+ See ssl3_send_server_key_exchange() in ssl/s3_srvr.c
+ */
+ if (type == EVP_PKEY_RSA || type == EVP_PKEY_DSA) {
+ keylen = EVP_PKEY_bits(pkey);
+ }
+
+ if (keylen > global.tune.ssl_default_dh_param) {
+ keylen = global.tune.ssl_default_dh_param;
+ }
+
+ if (keylen >= 8192) {
+ dh = local_dh_8192;
+ }
+ else if (keylen >= 4096) {
+ dh = local_dh_4096;
+ }
+ else if (keylen >= 2048) {
+ dh = local_dh_2048;
+ }
+ else {
+ dh = local_dh_1024;
+ }
+
+ return dh;
+}
+
/* Loads Diffie-Hellman parameter from a file. Returns 1 if loaded, else -1
if an error occured, and 0 if parameter not found. */
int ssl_sock_load_dh_params(SSL_CTX *ctx, const char *file)
@@ -321,29 +1063,6 @@
int ret = -1;
BIO *in;
DH *dh = NULL;
- /* If not present, use parameters generated using 'openssl dhparam 1024 -C':
- * -----BEGIN DH PARAMETERS-----
- * MIGHAoGBAJJAJDXDoS5E03MNjnjK36eOL1tRqVa/9NuOVlI+lpXmPjJQbP65EvKn
- * fSLnG7VMhoCJO4KtG88zf393ltP7loGB2bofcDSr+x+XsxBM8yA/Zj6BmQt+CQ9s
- * TF7hoOV+wXTT6ErZ5y5qx9pq6hLfKXwTGFT78hrE6HnCO7xgtPdTAgEC
- * -----END DH PARAMETERS-----
- */
- static const unsigned char dh1024_p[] = {
- 0x92, 0x40, 0x24, 0x35, 0xC3, 0xA1, 0x2E, 0x44, 0xD3, 0x73, 0x0D, 0x8E,
- 0x78, 0xCA, 0xDF, 0xA7, 0x8E, 0x2F, 0x5B, 0x51, 0xA9, 0x56, 0xBF, 0xF4,
- 0xDB, 0x8E, 0x56, 0x52, 0x3E, 0x96, 0x95, 0xE6, 0x3E, 0x32, 0x50, 0x6C,
- 0xFE, 0xB9, 0x12, 0xF2, 0xA7, 0x7D, 0x22, 0xE7, 0x1B, 0xB5, 0x4C, 0x86,
- 0x80, 0x89, 0x3B, 0x82, 0xAD, 0x1B, 0xCF, 0x33, 0x7F, 0x7F, 0x77, 0x96,
- 0xD3, 0xFB, 0x96, 0x81, 0x81, 0xD9, 0xBA, 0x1F, 0x70, 0x34, 0xAB, 0xFB,
- 0x1F, 0x97, 0xB3, 0x10, 0x4C, 0xF3, 0x20, 0x3F, 0x66, 0x3E, 0x81, 0x99,
- 0x0B, 0x7E, 0x09, 0x0F, 0x6C, 0x4C, 0x5E, 0xE1, 0xA0, 0xE5, 0x7E, 0xC1,
- 0x74, 0xD3, 0xE8, 0x4A, 0xD9, 0xE7, 0x2E, 0x6A, 0xC7, 0xDA, 0x6A, 0xEA,
- 0x12, 0xDF, 0x29, 0x7C, 0x13, 0x18, 0x54, 0xFB, 0xF2, 0x1A, 0xC4, 0xE8,
- 0x79, 0xC2, 0x3B, 0xBC, 0x60, 0xB4, 0xF7, 0x53,
- };
- static const unsigned char dh1024_g[] = {
- 0x02,
- };
in = BIO_new(BIO_s_file());
if (in == NULL)
@@ -353,28 +1072,32 @@
goto end;
dh = PEM_read_bio_DHparams(in, NULL, ctx->default_passwd_callback, ctx->default_passwd_callback_userdata);
- if (!dh) {
+ if (dh) {
+ ret = 1;
+ SSL_CTX_set_tmp_dh(ctx, dh);
+ /* Setting ssl default dh param to the size of the static DH params
+ found in the file. This way we know that there is no use
+ complaining later about ssl-default-dh-param not being set. */
+ global.tune.ssl_default_dh_param = DH_size(dh) * 8;
+ }
+ else {
/* Clear openssl global errors stack */
ERR_clear_error();
- dh = DH_new();
- if (dh == NULL)
- goto end;
+ if (global.tune.ssl_default_dh_param <= 1024) {
+ /* we are limited to DH parameter of 1024 bits anyway */
+ local_dh_1024 = ssl_get_dh_1024();
+ if (local_dh_1024 == NULL)
+ goto end;
- dh->p = BN_bin2bn(dh1024_p, sizeof(dh1024_p), NULL);
- if (dh->p == NULL)
- goto end;
-
- dh->g = BN_bin2bn(dh1024_g, sizeof(dh1024_g), NULL);
- if (dh->g == NULL)
- goto end;
+ SSL_CTX_set_tmp_dh(ctx, local_dh_1024);
+ }
+ else {
+ SSL_CTX_set_tmp_dh_callback(ctx, ssl_get_tmp_dh);
+ }
ret = 0; /* DH params not found */
}
- else
- ret = 1;
-
- SSL_CTX_set_tmp_dh(ctx, dh);
end:
if (dh)
@@ -559,6 +1282,16 @@
}
#endif
+#ifdef SSL_CTRL_SET_TLSEXT_STATUS_REQ_CB
+ ret = ssl_sock_load_ocsp(ctx, path);
+ if (ret < 0) {
+ if (err)
+ memprintf(err, "%s '%s.ocsp' is present and activates OCSP but it is impossible to compute the OCSP certificate ID (maybe the issuer could not be found)'.\n",
+ *err ? *err : "", path);
+ return 1;
+ }
+#endif
+
#ifndef SSL_CTRL_SET_TLSEXT_HOSTNAME
if (bind_conf->default_ctx) {
memprintf(err, "%sthis version of openssl cannot load multiple SSL certificates.\n",
@@ -589,6 +1322,10 @@
*end = 0;
while ((de = readdir(dir))) {
+ end = strrchr(de->d_name, '.');
+ if (end && (!strcmp(end, ".issuer") || !strcmp(end, ".ocsp")))
+ continue;
+
snprintf(fp, sizeof(fp), "%s/%s", path, de->d_name);
if (stat(fp, &buf) != 0) {
memprintf(err, "%sunable to stat SSL certificate from file '%s' : %s.\n",
@@ -724,6 +1461,7 @@
#ifndef SSL_MODE_RELEASE_BUFFERS /* needs OpenSSL >= 1.0.0 */
#define SSL_MODE_RELEASE_BUFFERS 0
#endif
+
int ssl_sock_prepare_ctx(struct bind_conf *bind_conf, SSL_CTX *ctx, struct proxy *curproxy)
{
int cfgerr = 0;
@@ -740,6 +1478,16 @@
SSL_MODE_ENABLE_PARTIAL_WRITE |
SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER |
SSL_MODE_RELEASE_BUFFERS;
+ STACK_OF(SSL_CIPHER) * ciphers = NULL;
+ SSL_CIPHER * cipher = NULL;
+ char cipher_description[128];
+ /* The description of ciphers using an Ephemeral Diffie Hellman key exchange
+ contains " Kx=DH " or " Kx=DH(". Beware of " Kx=DH/",
+ which is not ephemeral DH. */
+ const char dhe_description[] = " Kx=DH ";
+ const char dhe_export_description[] = " Kx=DH(";
+ int idx = 0;
+ int dhe_found = 0;
/* Make sure openssl opens /dev/urandom before the chroot */
if (!ssl_initialize_random()) {
@@ -828,6 +1576,53 @@
cfgerr++;
}
+ /* If tune.ssl.default-dh-param has not been set and
+ no static DH params were in the certificate file. */
+ if (global.tune.ssl_default_dh_param == 0) {
+ ciphers = ctx->cipher_list;
+
+ if (ciphers) {
+ for (idx = 0; idx < sk_SSL_CIPHER_num(ciphers); idx++) {
+ cipher = sk_SSL_CIPHER_value(ciphers, idx);
+ if (SSL_CIPHER_description(cipher, cipher_description, sizeof (cipher_description)) == cipher_description) {
+ if (strstr(cipher_description, dhe_description) != NULL ||
+ strstr(cipher_description, dhe_export_description) != NULL) {
+ dhe_found = 1;
+ break;
+ }
+ }
+ }
+
+ if (dhe_found) {
+ Warning("Setting tune.ssl.default-dh-param to 1024 by default, if your workload permits it you should set it to at least 2048. Please set a value >= 1024 to make this warning disappear.\n");
+ }
+ }
+
+ global.tune.ssl_default_dh_param = 1024;
+ }
+
+#ifndef OPENSSL_NO_DH
+ if (global.tune.ssl_default_dh_param >= 1024) {
+ if (local_dh_1024 == NULL) {
+ local_dh_1024 = ssl_get_dh_1024();
+ }
+ if (global.tune.ssl_default_dh_param >= 2048) {
+ if (local_dh_2048 == NULL) {
+ local_dh_2048 = ssl_get_dh_2048();
+ }
+ if (global.tune.ssl_default_dh_param >= 4096) {
+ if (local_dh_4096 == NULL) {
+ local_dh_4096 = ssl_get_dh_4096();
+ }
+ if (global.tune.ssl_default_dh_param >= 8192 &&
+ local_dh_8192 == NULL) {
+ local_dh_8192 = ssl_get_dh_8192();
+ }
+ }
+ }
+ }
+#endif /* OPENSSL_NO_DH */
+
SSL_CTX_set_info_callback(ctx, ssl_sock_infocbk);
#if OPENSSL_VERSION_NUMBER >= 0x00907000L
SSL_CTX_set_msg_callback(ctx, ssl_sock_msgcbk);
@@ -1888,21 +2683,25 @@
return (char *)SSL_get_version(conn->xprt_ctx);
}
-/* returns common name, NULL terminated, from client certificate, or NULL if none */
-char *ssl_sock_get_common_name(struct connection *conn)
+/* Extract peer certificate's common name into the chunk dest
+ * Returns
+ * the len of the extracted common name
+ * or 0 if no CN found in DN
+ * or -1 on error case (i.e. no peer certificate)
+ */
+int ssl_sock_get_remote_common_name(struct connection *conn, struct chunk *dest)
{
X509 *crt = NULL;
X509_NAME *name;
- struct chunk *cn_trash;
const char find_cn[] = "CN";
const struct chunk find_cn_chunk = {
.str = (char *)&find_cn,
.len = sizeof(find_cn)-1
};
- char *result = NULL;
+ int result = -1;
if (!ssl_sock_is_ssl(conn))
- return NULL;
+ goto out;
/* SSL_get_peer_certificate, it increase X509 * ref count */
crt = SSL_get_peer_certificate(conn->xprt_ctx);
@@ -1913,13 +2712,8 @@
if (!name)
goto out;
- cn_trash = get_trash_chunk();
- if (ssl_sock_get_dn_entry(name, &find_cn_chunk, 1, cn_trash) <= 0)
- goto out;
- cn_trash->str[cn_trash->len] = '\0';
- result = cn_trash->str;
-
- out:
+ result = ssl_sock_get_dn_entry(name, &find_cn_chunk, 1, dest);
+out:
if (crt)
X509_free(crt);
|
[-]
[+]
|
Changed |
haproxy-1.5.3.tar.gz/src/standard.c
^
|
@@ -38,6 +38,12 @@
char itoa_str[NB_ITOA_STR][171];
int itoa_idx = 0; /* index of next itoa_str to use */
+/* sometimes we'll need to quote strings (eg: in stats), and we don't expect
+ * to quote strings larger than a max configuration line.
+ */
+char quoted_str[NB_QSTR][QSTR_SIZE + 1];
+int quoted_idx = 0;
+
/*
* unsigned long long ASCII representation
*
@@ -444,6 +450,39 @@
return (n) ? ultoa_r(n, buffer, size) : (alt ? alt : "");
}
+/* returns a locally allocated string containing the quoted encoding of the
+ * input string. The output may be truncated to QSTR_SIZE chars, but it is
+ * guaranteed that the string will always be properly terminated. Quotes are
+ * encoded by doubling them as is commonly done in CSV files. QSTR_SIZE must
+ * always be at least 4 chars.
+ */
+const char *qstr(const char *str)
+{
+ char *ret = quoted_str[quoted_idx];
+ char *p, *end;
+
+ if (++quoted_idx >= NB_QSTR)
+ quoted_idx = 0;
+
+ p = ret;
+ end = ret + QSTR_SIZE;
+
+ *p++ = '"';
+
+ /* always keep 3 chars to support passing "" and the ending " */
+ while (*str && p < end - 3) {
+ if (*str == '"') {
+ *p++ = '"';
+ *p++ = '"';
+ }
+ else
+ *p++ = *str;
+ str++;
+ }
+ *p++ = '"';
+ return ret;
+}
+
/*
* Returns non-zero if character <s> is a hex digit (0-9, a-f, A-F), else zero.
*
@@ -1156,6 +1195,40 @@
return -1;
}
+/* Tries to convert a sockaddr_storage port to text form. Upon success, the
+ * address family is returned so that it's easy for the caller to adapt to the
+ * output format. Zero is returned if the address family is not supported. -1
+ * is returned upon error, with errno set. AF_INET, AF_INET6 and AF_UNIX are
+ * supported.
+ */
+int port_to_str(struct sockaddr_storage *addr, char *str, int size)
+{
+
+ uint16_t port;
+
+
+ if (size < 5)
+ return 0;
+ *str = '\0';
+
+ switch (addr->ss_family) {
+ case AF_INET:
+ port = ((struct sockaddr_in *)addr)->sin_port;
+ break;
+ case AF_INET6:
+ port = ((struct sockaddr_in6 *)addr)->sin6_port;
+ break;
+ case AF_UNIX:
+ memcpy(str, "unix", 5);
+ return addr->ss_family;
+ default:
+ return 0;
+ }
+
+ snprintf(str, size, "%u", ntohs(port));
+ return addr->ss_family;
+}
+
/* will try to encode the string <string> replacing all characters tagged in
* <map> with the hexadecimal representation of their ASCII-code (2 digits)
* prefixed by <escape>, and will store the result between <start> (included)
@@ -2416,8 +2489,8 @@
const char *strnistr(const char *str1, int len_str1, const char *str2, int len_str2)
{
char *pptr, *sptr, *start;
- uint slen, plen;
- uint tmp1, tmp2;
+ unsigned int slen, plen;
+ unsigned int tmp1, tmp2;
if (str1 == NULL || len_str1 == 0) // search pattern into an empty string => search is not found
return NULL;
|
[-]
[+]
|
Changed |
haproxy-1.5.3.tar.gz/src/stick_table.c
^
|
@@ -601,15 +601,17 @@
* Process a fetch + format conversion as defined by the sample expression <expr>
* on request or response considering the <opt> parameter. Returns either NULL if
* no key could be extracted, or a pointer to the converted result stored in
- * static_table_key in format <table_type>.
+ * static_table_key in format <table_type>. If <smp> is not NULL, it will be reset
+ * and its flags will be initialized so that the caller gets a copy of the input
+ * sample, and knows why it was not accepted (eg: SMP_F_MAY_CHANGE is present).
*/
struct stktable_key *stktable_fetch_key(struct stktable *t, struct proxy *px, struct session *l4, void *l7,
- unsigned int opt,
- struct sample_expr *expr)
+ unsigned int opt, struct sample_expr *expr, struct sample *smp)
{
- struct sample *smp;
+ if (smp)
+ memset(smp, 0, sizeof(*smp));
- smp = sample_process(px, l4, l7, opt, expr, NULL);
+ smp = sample_process(px, l4, l7, opt, expr, smp);
if (!smp)
return NULL;
|
|
Deleted |
haproxy-1.5.tar.gz
^
|