Adam Ciarcinski
Adrian Chadd <adrian@squid-cache.org>
+ Aecio F. <aecioneto@gmail.com>
Alan Mizrahi <alan@mizrahi.com.ve>
+ Alan Nastac <mrness@gentoo.org>
+ Aleksa <susulic@gmail.com>
+ Aleksa ??u??uli?? <susulic@gmail.com>
Alexander B. Demenshin <aldem@barnet.kharkov.ua>
Alexander Komyagin <komyagin@altell.ru>
+ Alexander Lukyanov <lav@netis.ru>
Alexander Lukyanov <lav@yar.ru>
Alexandre Chappaz <alexandrechappaz@gmail.com>
+ Alexandre SIMON <alexandre.simon@ciril.fr>
+ Alex Dowad <alexinbeijing@gmail.com>
Alexey Veselovsky <alexey.veselovsky@eykontech.com>
Alexis Robert <alexis.robert@gmail.com>
Alex Rousskov <rousskov@measurement-factory.com>
+ Alex Rousskov <rousskov@squid-cache.org>
Alin Nastac <mrness@gentoo.org>
Alter <alter@alter.org.ua>
Amos Jeffries <amosjeffries@squid-cache.org>
Amos Jeffries <squid3@treenet.co.nz>
+ Amos <squid3@treenet.co.nz>
Anatoli <me@anatoli.ws>
Andrea Gagliardi <andrea@netlite.it>
Andreas Jaeger <aj@suse.com>
Andreas Lamprecht <Andreas.Lamprecht@siemens.at>
Andres Kroonmaa <andre@ml.ee>
+ Andrew Balabohin
Andrew Beverley <andy@andybev.com>
Andrew Doran <ad@interlude.eu.org>
+ Andrew Evdokimov <ae@elahi.ru>
Andrew Hoying <andrew_hoying@blm.gov>
Andrew Tridgell
Andrey Shorin <tolsty@tushino.com>
+ Anonymous Pootle User
Anonymous <redskilldough@gmail.com>
Ansgar Hockmann <Ansgar.Hockmann@hrz.uni-dortmund.de>
Anthony Baxter <arb@connect.com.au>
Antonino Iannella
+ Arjan de Vet <Arjan.deVet@adv.IAEhv.nl>
Arjan de Vet <Arjan.deVet@adv.iae.nl>
Arkin <arkin.yang@gmail.com>
Arno Streuli <astreuli@gmail.com>
+ Arthur <arthur@psw.ro>
+ Arthur <arthurtumanyan@yahoo.com>
Arthur Tumanyan <arthurtumanyan@yahoo.com>
Assar Westerlund <assar@pdc.kth.se>
Automatic source maintenance <squidadm@squid-cache.org>
Axel Westerhold <ml.awesterhold@dts.de>
+ Barry Dobyns <barry@dobyns.com>
Benjamin Kerensa <bkerensa@ubuntu.com>
- benno@jeamland.net
+ Benno Rice <benno@jeamland.net>
Benno Rice <benno@squid-cache.org>
Bernard <fli4l.charrier@free.fr>
Bertrand Jacquin <beber@meleeweb.net>
Bill Welliver
Bojan Smojver <bojan@rexursive.com>
Brad Smith <brad@comstyle.com>
+ Bratislav <batailic@gmail.com>
Brian Degenhardt <bmd@mp3.com>
Brian Denehy <B-Denehy@adfa.oz.au>
Brian <hiryuu@envisiongames.net>
Bruce Murphy <pack-squid@rattus.net>
Carson Gaspar (carson@lehman.com, carson@cs.columbia.edu)
+ Cephas <squidwin@gmail.com>
+ Chad E. Naugle <chad.naugle@travimp.com>
+ Chad Naugle <chad.naugle@travimp.com>
Changming <me@sunchangming.com>
+ Chao <chao_83@126.com>
Chris Hills <chaz@chaz6.com>
+ Christian Wittmer <chris@computersalat.de>
Christopher Kerr
+ Christophe Saout <christophe@saout.de>
Christoph Lechleitner <lech@ibcl.at>
+ Christos Tsantilas <christos@chtsanti.net>
Christos Tsantilas <chtsanti@users.sourceforge.net>
Cloyce <cloyce.spradling@sun.com>
+ Clytie Siddall <clytie@riverland.net.au>
+ Colin Coe <colin.coe@gmail.com>
Constantin Rack
Cord Beermann <cord@cc.fh-lippe.de>
Daniel Beschorner <daniel.beschorner@evlks.de>
Daniel O'Callaghan <danny@miriworld.its.unimelb.EDU.AU>
+ Daniel Walter <d.walter@0x90.at>
+ Dan Searle <dan.searle@censornet.com>
+ David Hill <david.hill@ubisoft.com>
David Isaacs <david.isaacs@sbhs.nsw.edu.au>
David J N Begley
David Luyer <david@luyer.net>
David Luyer <luyer@ucs.uwa.edu.au>
+ David Parks <davidparks21@yahoo.com>
+ Declan White <declanw@is.bbc.co.uk>
+ Dennis Felippa <dennis@infologika.com.br>
Dennis Glatting
- Dhaval Varia
+ Dhaval Varia <dhavalkvaria@gmail.com>
Diego Woitasen <diegows@xtech.com.ar>
- Dmitry Kurochkin
+ D Kazarov <d.y.kazarov@mail.ru>
+ Dmitry Kurochkin <dmitry.kurochkin@measurement-factory.com>
Don Hopkins <dhopkins@DonHopkins.com>
Doug Dixon <doug.dixon@gmail.com>
Doug Urner <dlu@bsdi.com>
Dragutin Cirkovic <painkiller@gromnet.net>
+ drserge <drserge@inbox.ru>
Dr. Tilmann Bubeck <t.bubeck@reinform.de>
Duane Wessels <wessels@squid-cache.org>
Dustin J. Mitchell
Ed Knowles <ed@fatboy.geog.unsw.edu.au>
+ Edward Chernenko <edwardspec@gmail.com>
Edward Moy <moy@parc.xerox.com>
+ Eldar Akchurin <al.akchurin@googlemail.com>
Eliezer Croitoru <eliezer@ngtech.co.il>
Elmar Vonlanthen <Elmar.Vonlanthen@united-security-providers.ch>
Emilio Casbas <ecasbas@unav.es>
Endre Balint Nagy <bne@CareNet.hu>
+ Eray Aslan <eraya@a21an.org>
Eray Aslan <eray.aslan@caf.com.tr>
Eric Stern <estern@logisense.com>
Erik Hofman <erik.hofman@a1.nl>
Eugene Gladchenko <eugene@donpac.ru>
Evan Jones <ejones@uwaterloo.ca>
+ Evgeni <etg@setcom.bg>
Eygene Ryabinkin <rea@freebsd.org>
+ Fabian Hugelshofer <fh@open.ch>
fancyrabbit <fancyrabbit@gmail.com>
Felix Meschberger <felix.meschberger@day.com>
+ Feshchuk Yuriy <swopster@meta.ua>
Finn Thain <fthain@telegraphics.com.au>
Flavio Pescuma <flavio@marasystems.com>
+ Florent <fcarli@gmail.com>
folkert <folkert@vanheusden.com>
Francesco Chemolli <kinkie@squid-cache.org>
Francesco <kinkie@squid-cache.org>
Frank Balluffi
Frank Schmirler <squid@schmirler.de>
Frederic Bourgeois <fredbmail@free.fr>
+ Fred <fred.maranhao@gmail.com>
+ F Wolff <friedel@translate.org.za>
+ Fyodor <fygrave@gmail.com>
Geoff Keating <Geoff.Keating@anu.edu.au>
George Michaelson <ggm@connect.com.au>
Georgy Salnikov <sge@nmr.nioch.nsc.ru>
Gerard Eviston
Gerben Wierda <Gerben_Wierda@RnA.nl>
+ Gergely <mail.gery@gmail.com>
Giancarlo Razzolini <linux-fan@onda.com.br>
Gilles Espinasse <g.esp@free.fr>
+ gkeeling <grm___k@hotmail.com>
Glen Gibb <grg@ridley.unimelb.edu.au>
Glenn Chisholm <glenn@ircache.net>
Glen Newton <glen.newton@nrc.ca>
Graham Keeling <graham@equiinet.com>
Guido Serassio <guido.serassio@acmeconsulting.it>
Guido Serassio <serassio@squid-cache.org>
+ Gustavo Zacarias <gustavo@zacarias.com.ar>
+ Guy Helmer <ghelmer@palisadesys.com>
Hank Hampel <hh@nr-city.net>
Hasso Tepper <hasso@estpak.ee>
- Henrik Nordstr?m <henrik@hlaptop.localdomain>
+ helix84 <helix84@centrum.sk>
Henrik Nordstrom <henrik@henriknordstrom.net>
Henrik Nordstrom <hno@squid-cache.org>
Hide Nagaoka <hide@cc.meisei-u.ac.jp>
- hno
+ HONDA Hirofumi <honda.hirofumi@nttcom.co.jp>
+ Hussam Al-Tayeb <hussam@visp.net.lb>
Ian Castle <ian.castle@coldcomfortfarm.net>
Ian Turner <vectro@pipeline.com>
Igor Vinokurov <igor@cs.ibank.ru>
+ IIDA Yosiaki <y-iida@secom.co.jp>
+ isaac <isaacarsenal@gmail.com>
Isnard <isnardjaquet@gmail.com>
+ Ivan Mas??r <helix84@centrum.sk>
Jakob Bohm <jb-debbugs@wisemo.com>
Jakub Wilk <ubanus@users.sf.net>
+ James Bowe <minijb@gmail.com>
James Brotchie <brotchie@gmail.com>
James R Grinter <jrg@demon.net>
+ Jan Klemkow <j.klemkow@wemelug.de>
Jan Niehusmann <jan@anduin.gondor.mcs.de>
Jan Sievers <sievers@zedat.fu-berlin.de>
Jean-Francois Micouleau <Jean-Francois.Micouleau@utc.fr>
Jens-S. V?ckler <voeckler@rvs.uni-hannover.de>
Jeremy Allison
Jerry Murdock <jmurdock@itraktech.com>
+ Jiri Skala <jaskalnik@gmail.com>
+ Jiri Skala <jskala@redhat.com>
Joachim Bauch <jojo@fistofbenztown.de>
Joachim Bauch (mail@joachim-bauch.de)
Joao Alves Neto <alves_joao@hotmail.com>
Jochen Obalek
Jochen Voss <voss@seehuhn.de>
+ Joe Crayne <oh.hellojoe@gmail.com>
Joe Ramey <ramey@csc.ti.com>
Joe Ramey <ramey@jello.csc.ti.com>
+ Joerg Lehrke <jlehrke@noc.de>
Johnathan Conley <johnathan.conley@gmail.com>
John Dilley <jad@hpl.hp.com>
John Saunders <johns@rd.scitec.com.au>
John Xue <xgxjohn@gmail.com>
Jonathan Larmour <JLarmour@origin-at.co.uk>
+ Jonathan Wolfe <jonathan.wolfe@gmail.com>
Jon Kinred
Jon Thackray <jrmt@uk.gdscorp.com>
+ Jorge Ivan Burgos Aguilar <jorgeivanburgosaguilar@gmail.com>
+ Jose-Marcio Martins da Cruz <Jose-Marcio.Martins@mines-paristech.fr>
+ Joshua Root <jmr@macports.org>
Joshua Root <josh+squid@root.id.au>
JPP <jpp1@frws.com>
+ Juan <jdsq12@yahoo.es>
Juerg Michel
+ Julien Pinon <jpinon@olfeo.com>
+ Karl Benoit <karl.isatwork@gmail.com>
Kieran Whitbread <k.j.whitbread@qmul.ac.uk>
- Kinkie <kinkie@squid-cache.org>
- kinkie@squid-cache.org
Klaubert Herr <klaubert@gmail.com>
Klaus Singvogel <kssingvo@suse.de>
Kolics Bertold <bertold@tohotom.vein.hu>
Lab10 <lab10@bt-anlagenbau.at>
Laszlo Attilla Toth <panther@balabit.hu>
Leeann Bent <lbent@cs.ucsd.edu>
+ Leonid Evdokimov <leon@darkk.net.ru>
libit <sambabug.lb@gmail.com>
Luigi Gangitano <luigi@debian.org>
+ Luis Daniel Lucio Quiroz <dlucio@okay.com.mx>
+ Lukas B??gelei <unknown>
Luke Howard <lukeh@vurt.schnet.edu.au>
Lutz Donnerhacke <lutz@iks-jena.de>
Manu Garg <manugarg@gmail.com>
- Marcus Kool
+ Marcello Romani <marcello.romani@libero.it>
+ Marcin Wisnicki <mwisnicki@gmail.com>
+ Marco Beck <mbeck@miamod.de>
+ Marcus Kool <marcus.kool@urlfilterdb.com>
Marc van Selm <selm@cistron.nl>
Marin Stavrev <mstavrev@gmail.com>
Marios Makassikis <mmakassikis@gmail.com>
Mark Treacy <mark@aone.com.au>
Markus Gyger <mgyger@itr.ch>
Markus Moeller <huaraz@moeller.plus.com>
+ Markus Moeller (markus_moeller at compuserve.com)
Markus Rietzler <markus.rietzler@rzf.fin-nrw.de>
Markus Stumpf <maex@Space.NET>
Martin Hamilton <martinh@gnu.org>
Martin Hamilton <martin@mrrl.lut.ac.uk>
+ Martin Huter <mhuter@barracuda.com>
Martin Huter <m.huter@phion.com>
Martin Stolle <martin.stolle@ekom21.de>
Masashi Fujita <objectx@bandit.co.jp>
Massimo Zito <zmax.linkedin at gmail dot com>
+ Mathias Fischer <maf@open.ch>
Matthew Morgan <atcs.matthew@gmail.com>
Matthias Pitzl <silamael@coronamundi.de>
+ Matthias "Silamael" <Silamael@coronamundi.de>
Max Okumoto <okumoto@ucsd.edu>
Merik Karman
<mgd@swarm.org>
Michael O'Reilly <michael@metal.iinet.net.au>
Michael Pelletier <mikep@comshare.com>
Michael van Elst
+ Michael Weiser <michael@weiser.dinsnail.net>
Michal Luscon <mluscon@redhat.com>
Miguel A.L. Paraz <map@iphil.net>
Mike Groeneweg <mikeg@scorpion.murdoch.edu.au>
+ Mike Mitchell <mike.mitchell@sas.com>
Mike Mitchell <Mike.Mitchell@sas.com>
Mikio Kishi <mkishi@104.net>
+ Milen Pankov <mail@milen.pankov.eu>
Ming Fu <mfu@watchguard.com>
Miquel van Smoorenburg <miquels@cistron.nl>
Moez Mahfoudh <moez.mahfoudh@imag.fr>
+ Mohsen Saeedi <mohsen.saeedi@gmail.com>
Mukaigawa Shin'ichi <shin@nff.ncl.omron.co.jp>
Nathan Hoad <nathan@getoffmalawn.com>
Neil Murray <neil@aone.com.au>
+ nglnx - Rosetta Project
Niall Doherty <ndoherty@eei.ericsson.se>
Nick Rogers <ncrogers@gmail.com>
Nikolai Gorchilov <niki@x3me.net>
'noloader' <noloader@gmail.com>
+ Ole Christensen <olechristensende@aol.de>
+ Oliver Dumschat <necromot@googlemail.com>
Oliver Hookins
Olivier Montanuy
+ Olivier W.
+ OpenSolaris Project
Oskar Pearson <oskar@is.co.za>
Paul Z <paulz42@gmail.com>
+ Pavel Timofeev
Pawel Worach <pawel.worach@gmail.com>
Pedro Lineu Orso <orso@pop.hsbcbamerindus.com.br>
Pedro Ribeiro <pribeiro@isel.pt>
Pete Bentley <pete@demon.net>
- Peter Eisenhauer <pe@pipetronix.de>
Peter Hidas <peter.hidas@safeland.hu>
+ Peter Payne
Peter Pramberger <peter@pramberger.at>
Philip Allison <philip.allison@smoothwall.net>
Philippe Lantin <plantin@cobaltgroup.com>
+ Phil Oester <kernel@linuxace.com>
Pierangelo Masarati <ando@sys-net.it>
+ Pierre LALET <pierre.lalet@cea.fr>
Pierre-Louis Brenac <brenacp@esiee.fr>
Pierre-Louis BRENAC <brenacp@esiee.fr>
Poul-Henning Kamp <phk@login.dknet.dk>
Priyanka Gupta <priyanka@icelero.com>
Przemek Czerkas <pczerkas@mgmnet.pl>
Rabellino Sergio (rabellino@di.unito.it)
+ Rafael Martinez <rmartine@fdi.ucm.es>
Rafael Martinez Torres <rmartine@fdi.ucm.es>
Rafal Ramocki <maniac@sistbg.net>
Rajiv Desai <rajiv@maginatics.com>
Ramon de Carvalho <ramondecarvalho@yahoo.com.br>
Regardt van de Vyver <squid@vdvyver.net>
Regents of the University of California (UCSD)
+ Reinhard Posmyk <Reinhard.Posmyk@arxes.de>
Reinhard Sojka <reinhard.sojka@parlament.gv.at>
Rene Geile <rene.geile@t-online.de>
+ Ren? Geile <rene.geile@t-online.de>
Reuben Farrelly <reuben@reub.net>
Richard Huveneers <richard@hekkihek.hacom.nl>
Richard Huveneers <Richard.Huveneers@hekkihek.hacom.nl>
Richard Wall <richard.wall@appliansys.com>
Robert Collins <rbtcollins@hotmail.com>
Robert Collins <robertc@robertcollins.net>
+ Robert <Dessa@gmake.de>
Robert Forster
+ Robert Walsh <robert.walsh@bbn.com>
Robin Elfrink <robin@a1.nl>
Rodrigo Campos <rodrigo@geekbunker.org>
Rodrigo Campos (rodrigo@geekbunker.org)
Rodrigo Rubira Branco <rodrigo@kernelhacking.com>
Rodrigo Rubira Branco <rrbranco@br.ibm.com>
Ron Gomes <rrg@ny.ubs.com>
- rousskov
+ R Phillips <r.phillips@uq.edu.au>
Russell Street <r.street@auckland.ac.nz>
Russell Vincent <vincent@ucthpx.uct.ac.za>
Ryan Troll <ryan+@andrew.cmu.edu>
Samba Project
+ Santiago Garcia Mantinan <manty@debian.org>
+ Scott James Remnant <scott@netsplit.com>
Scott Schram <scott@schram.net>
+ Sean Critica <sean.critica@gmail.com>
+ Sebastian Krahmer <krahmer@suse.com>
Sebastien Wenske <sebastien@wenske.fr>
+ Sergey Merzlikin <sm@smsoft.ru>
Sergio Rabellino <rabellino@di.unito.it>
Shigechika Aikawa <shige@luck.imasy.or.jp>
Silamael <Silamael@coronamundi.de>
- squidadm@squid-cache.org
Stefan Fritsch <sf@sfritsch.de>
Stefano Cordibella <stefano.cordibella@edalab.it>
Stephen R. van den Berg <srb@cuci.nl>
+ Stephen Thorne <stephen@thorne.id.au>
Steve Bennett <S.Bennett@lancaster.ac.uk>
Steve Hill <steve@opendium.com>
+ Steven Lawrance <squid@moonlightdesign.org>
Steven Wilton <swilton@q-net.net.au>
Steve Snyder <swsnyder@snydernet.net>
Stewart Forster <slf@connect.com.au>
Stuart Henderson <sthen@openbsd.org>
+ Stuart Henderson <stu@spacehopper.org>
Susant Sahani <ssahani@redhat.com>
Svenx <svensven@gmail.com>
Taavi Talvik <taavi@uninet.ee>
Taketo Kabe <kabe@shiratori.riec.tohoku.ac.jp>
The Measurement Factory <info@measurement-factory.com>
+ The Squid Software Foundation
Thomas De Schampheleire <thomas.de.schampheleire@gmail.com>
Thomas Hozza <thozza@redhat.com>
Thomas-Martin Seck <tmseck@netcologne.de>
Thomas Ristic <thr@bootet.net>
Thomas Weber <x@4t2.com>
Tianyin Xu <tixu@cs.ucsd.edu>
+ Tilmann Bubeck <t.bubeck@reinform.de>
+ Tim Brown <squid-cache@machine.org.uk>
+ Timo Teras <timo.teras@iki.fi>
+ Timo Tseras <timo.teras@iki.fi>
Tim Starling <tstarling@wikimedia.org>
Todd C. Miller <Todd.Miller@courtesan.com>
Tomas Hozza <thozza@redhat.com>
Tony Lorimer <tlorimer@au.mdis.com>
+ Tsantilas Christos <chtsanti@users.sourceforge.net>
+ Unknown
Unknown FreeBSD Contributor
Unknown - NetBSD Project
+ Various
+ Various Translators
+ Victor Jose Hernandez Gomez <vjhergom@cic.upo.es>
Vince Brimhall
Vincent Regnard
Vitaliy Matytsyn (main) <vm@if.bank.gov.ua>
Vitaliy Matytsyn <vm@if.bank.gov.ua>
vollkommen <vollkommen@gmx.net>
+ Walter <bundestrojaner2@googlemail.com>
+ Wang DaQing <wdq@bigfoot.com>
+ Warren Baker <warren@decoy.co.za>
Wesha <wesha@iname.com>
Will Roberts <squid@bigwillystyle42.com>
+ Wojciech Zatorski <zator@bg.szczecin.pl>
Wojtek Sylwestrzak <W.Sylwestrzak@icm.edu.pl>
Wolfgang Breyha <wbreyha@gmx.net>
Wolfgang Nothdurft <wolfgang@linogate.de>
+ Xavier Redon <xavier.redon@polytech-lille.fr>
+ yabuki <yabuki@sraoss.co.jp>
+ Yannick Bergeron <yaberger@ca.ibm.com>
+ Yuhua Wu <ywu@bitglass.com>
Zhanpeng Chen <lowstz@gmail.com>
==============================================================================
+errors/:
+
+ * Translation Snippets provided by Squid Project Translators held in
+ * copyright for open distribution.
+ *
+ * Translation Snippets provided by Rosetta Project Translators held in
+ * copyright for open distribution.
+ *
+ * Copyright 2009
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+
+
+see TRANSLATORS file for current contributing translators holding copyrights.
+
+==============================================================================
+
errors/errorpage.css:
Stylesheet for Squid Error pages
+Changes to squid-3.5.3 (28 Mar 2015):
+
+ - Regression Bug 4213: negotiate_kerberos_auth: freeing non-dynamic memory
+ - Regression Bug 4206: Incorrect connection close on expect:100-continue
+ - Bug 4204: ./configure does not abort when required helpers cannot be built
+ - Bug 3805: support shared memory on MacOS X in Mem::IPC::Segment
+ - Bug 2907: high CPU usage on CONNECT when using delay pools
+ - basic_getpwnam_auth: fail authentication on crypt() failures
+ - basic_nis_auth: fail authentication on crypt() failures
+ - ext_kerberos_ldap_group_acl: Heimdal support improvements
+ - ext_wbinfo_group_acl: Perl 5.20 support
+ - ... and several compile issues
+
Changes to squid-3.5.2 (18 Feb 2015):
- Regression Bug 4176: Digest auth too many helper lookups
+/*
+ * Copyright (C) 1996-2015 The Squid Software Foundation and contributors
+ *
+ * Squid software is distributed under GPLv2+ license and includes
+ * contributions from numerous individuals and organizations.
+ * Please see the COPYING and CONTRIBUTORS files for details.
+ */
+
To build and install the Squid Cache, type:
% ./configure --prefix=/usr/local/squid
% /usr/local/squid/sbin/squid
If you want to use the WWW interface to the Cache Manager, copy
-the cachemgr.cgi program into your httpd server's cgi-bin
+the tools/cachemgr.cgi program into your httpd server's cgi-bin
directory.
acl, http_access
Access control lists. This is important because it prevents people
- from stealing your network resources. To fill in the
- "localnet" ACL, use your network address (for instance 192.168.10.0
- your CIDR network mask (for instance 255.255.255.0 or /24):
+ from stealing your network resources.
+
+ Edit the "localnet" ACL definition to be your LAN network address
+ ranges in CIDR format. For instance:
- acl manager proto cache_object
- acl localhost src 127.0.0.1
acl localnet src 192.168.10.0/24
- http_access deny manager all
- http_access allow localnet
- http_access deny all
+ Add any other ACLs and edit the http_access lines to match your policy
+ requirements for use of the proxy. See Squid FAQ for more details.
cache_mgr
- Put here the e-mail address of the manager:
+ Put here the e-mail address of the manager.
+
+==============================================================================
+
+Some configuration lines which are optional but may be needed.
visible_hostname
- The host name you advertise for the cache.
+ The publicly visible host name advertised for the cache. This will
+ be used for URLs generated by Squid for clients to fetch certain
+ objects from.
cache_effective_user
If building your own squid; use ./configure --with-default-user=X
- If you must start Squid as root, find a safe user and group to run
+ You must start Squid as root, with a safe user and group to run
as after startup (typically "nobody" and "nogroup"). Do not use
"root", for security reasons.
-
-==============================================================================
-
-Some configuration lines which are optional but may be needed.
-
-
cache_dir ufs /usr/local/squid/var/cache 100 16 256
Add here (first number, here 100) the amount of hard disk space
start Squid at startup (it depends heavily on the Unix you use, you'll
typically have to modify something in a /etc/rc_something).
-This quick start file written by: Stephane Bortzmeyer and Duane
-Wessels.
+==============================================================================
+
+/*
+ * Copyright (C) 1996-2015 The Squid Software Foundation and contributors
+ *
+ * Squid software is distributed under GPLv2+ license and includes
+ * contributions from numerous individuals and organizations.
+ * Please see the COPYING and CONTRIBUTORS files for details.
+ */
+
+This quick start file written by:
+ Stephane Bortzmeyer and Duane Wessels.
The following organizations have supported the Squid Project by providing
their resources or funding various Squid development activities:
-@Squid-3.4:
+@Squid-4:
LaunchPad - http://launchpad.net/
- Provide Bazaar mirroring services and host the Squid-3 developer
+ Provide Bazaar mirroring services and host the Squid-3+ developer
project code.
-Messagenet - http://messagenet.it/
-
- Messagenet donated hardware and bandwidth for the wiki server
- and most continuous integration testing.
-
RackSpace - http://www.rackspace.com/
RackSpace donated a number of virtual machines from their cloud
infrastructure to support and extend the continuous integration
- testing infrastructure.
+ testing infrastructure, and since late 2014 to host many of the
+ Squid Project services.
+
+Squid Software Foundation - http://foundation.squid-cache.org/
+
+ The Foundation governs and facilitates Squid project activities,
+ providing the infrastructure and support framework for Squid
+ developers and users.
The Measurement Factory - http://www.measurement-factory.com/
Measurement Factory has constributed significant resources
- toward Squid-3 development and server maintenance.
+ toward Squid-3+ development and server maintenance.
Treehouse Networks, NZ - http://treenet.co.nz/
Treehouse Networks has contributed significant resources
- toward Squid-3 development and maintenance for their customer
+ toward Squid-3+ development and maintenance for their customer
gateways and CDN.
+@Squid-3.5:
+Messagenet - http://messagenet.it/
+
+ Messagenet donated hardware and bandwidth for the wiki server
+ and most continuous integration testing until late 2014 when
+ it was converted to a Squid Project core mirror server.
+
+@Squid-3.4:
+anonymoX GmbH - http://anonymox.net/
+
+ anonymoX contributed sponsorship and resources towards resolving
+ and testing bug fixes in high performance Squid-3.4 proxies.
+
@Squid-3.3:
iCelero - http://icelero.com/
Palisade Systems - http://www.palisadesys.com/
- Palisade Systems funded SSL Bump feature development in Squid3.
+ Palisade Systems funded initial SSL Bump feature development
+ in Squid-3.2.
@Squid-3.1:
Barefruit - http://www.barefruit.com/
KRB5INT_BEGIN_DECLS
#endif
#endif
+#if USE_APPLE_KRB5
+#define KERBEROS_APPLE_DEPRECATED(x)
+#endif
#include <krb5.h>
krb5_context kc; kc->max_skew = 1;
]])
KRB5INT_BEGIN_DECLS
#endif
#endif
+#if USE_APPLE_KRB5
+#define KERBEROS_APPLE_DEPRECATED(x)
+#endif
#include <krb5.h>
int main(int argc, char *argv[])
{
KRB5INT_BEGIN_DECLS
#endif
#endif
+#if USE_APPLE_KRB5
+#define KERBEROS_APPLE_DEPRECATED(x)
+#endif
#include <krb5.h>
int main(int argc, char *argv[])
{
#include <gss.h>
#endif
#else
+#if USE_APPLE_KRB5
+#define GSSKRB_APPLE_DEPRECATED(x)
+#endif
#if HAVE_GSSAPI_GSSAPI_H
#include <gssapi/gssapi.h>
#elif HAVE_GSSAPI_H
#include <gss.h>
#endif
#else
+#if USE_APPLE_KRB5
+#define GSSKRB_APPLE_DEPRECATED(x)
+#endif
#if HAVE_GSSAPI_GSSAPI_H
#include <gssapi/gssapi.h>
#elif HAVE_GSSAPI_H
AC_DEFUN([SQUID_CHECK_WORKING_KRB5],[
AC_CACHE_CHECK([for working krb5], squid_cv_working_krb5, [
AC_RUN_IFELSE([AC_LANG_SOURCE([[
+#if USE_APPLE_KRB5
+#define KERBEROS_APPLE_DEPRECATED(x)
+#endif
#if HAVE_KRB5_H
#if HAVE_BROKEN_SOLARIS_KRB5_H
#if defined(__cplusplus)
[Define to 1 if you have krb5_get_init_creds_opt_alloc]),)
AC_MSG_CHECKING([for krb5_get_init_creds_free requires krb5_context])
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
+ #if USE_APPLE_KRB5
+ #define KERBEROS_APPLE_DEPRECATED(x)
+ #endif
#include <krb5.h>
]],[[krb5_context context;
krb5_get_init_creds_opt *options;
AC_DEFINE(SQUID_SSLGETCERTIFICATE_BUGGY, 1)
AC_MSG_RESULT([yes])
],
- [])
+ [
+ AC_DEFINE(SQUID_SSLGETCERTIFICATE_BUGGY, 0)
+ AC_MSG_RESULT([cross-compile, assuming no])
+ ])
AC_MSG_CHECKING(whether the workaround for SSL_get_certificate works)
AC_RUN_IFELSE([
[
AC_MSG_RESULT([no])
],
-[])
+ [
+ AC_DEFINE(SQUID_USE_SSLGETCERTIFICATE_HACK, 0)
+ AC_MSG_RESULT([cross-compile, assuming no])
+ ])
SQUID_STATE_ROLLBACK(check_SSL_get_certificate)
])
#endif
CPPUNIT_ASSERT(undefinedAndFalseB);
CPPUNIT_ASSERT(!undefinedAndTrueB);
+
+#if UNDEFINED_FOO && UNDEFINED_FOO
+ bool undefinedAndUndefinedC = true;
+#else
+ bool undefinedAndUndefinedC = false;
+#endif
+#if !UNDEFINED_FOO && !UNDEFINED_FOO
+ bool notUndefinedAndNotUndefinedC = true;
+#else
+ bool notUndefinedAndNotUndefinedC = false;
+#endif
+ CPPUNIT_ASSERT(!undefinedAndUndefinedC);
+ CPPUNIT_ASSERT(notUndefinedAndNotUndefinedC);
}
/**
CPPUNIT_ASSERT(undefinedOrFalseB);
CPPUNIT_ASSERT(!undefinedOrTrueB);
+#if UNDEFINED_FOO || UNDEFINED_FOO
+ bool undefinedOrUndefinedC = true;
+#else
+ bool undefinedOrUndefinedC = false;
+#endif
+#if !UNDEFINED_FOO || !UNDEFINED_FOO
+ bool notUndefinedOrNotUndefinedC = true;
+#else
+ bool notUndefinedOrNotUndefinedC = false;
+#endif
+ CPPUNIT_ASSERT(notUndefinedOrNotUndefinedC);
+ CPPUNIT_ASSERT(!undefinedOrUndefinedC);
}
/* Typedefs for missing entries on a system */
/******************************************************/
+/*
+ * Ensure that standard type limits are defined for use
+ */
+#if __cplusplus >= 201103L
+#include <cstdint>
+#elif HAVE_STDINT_H
+#include <stdint.h>
+#endif
+
+/* explicit bit sizes */
+#if !defined(UINT32_MIN)
+#define UINT32_MIN 0x00000000L
+#endif
+#if !defined(UINT32_MAX)
+#define UINT32_MAX 0xFFFFFFFFL
+#endif
+
+#if !defined(INT_MAX)
+#define INT_MAX 0x7FFFFFFFL // hack but a safe bet (32-bit signed integer)
+#endif
+
+#if !defined(INT64_MIN)
+/* Native 64 bit system without strtoll() */
+#if defined(LONG_MIN) && (SIZEOF_LONG == 8)
+#define INT64_MIN LONG_MIN
+#else
+/* 32 bit system */
+#define INT64_MIN (-9223372036854775807LL-1LL)
+#endif
+#endif
+
+#if !defined(INT64_MAX)
+/* Native 64 bit system without strtoll() */
+#if defined(LONG_MAX) && (SIZEOF_LONG == 8)
+#define INT64_MAX LONG_MAX
+#else
+/* 32 bit system */
+#define INT64_MAX 9223372036854775807LL
+#endif
+#endif
+
/*
* ISO C99 Standard printf() macros for 64 bit integers
* On some 64 bit platform, HP Tru64 is one, for printf must be used
## Please see the COPYING and CONTRIBUTORS files for details.
##
-AC_INIT([Squid Web Proxy],[3.HEAD-BZR],[http://bugs.squid-cache.org/],[squid])
+AC_INIT([Squid Web Proxy],[4.0.0-BZR],[http://bugs.squid-cache.org/],[squid])
AC_PREREQ(2.61)
AC_CONFIG_HEADERS([include/autoconf.h])
AC_CONFIG_AUX_DIR(cfgaux)
# to be used by sub-commands
export enable_inline
-dnl
-dnl Check for atomic operations support in the compiler
-dnl
-AC_MSG_CHECKING([for GNU atomic operations support])
+# Check for atomic operations support in the compiler
+AC_CACHE_CHECK([for GNU atomic operations support],[squid_cv_gnu_atomics],[
AC_RUN_IFELSE([AC_LANG_PROGRAM([[
- int n = 0;
+#include <cstdint>
+ int32_t n_32 = 0;
+ uint64_t n_64 = 0;
]],[[
- __sync_add_and_fetch(&n, 10); // n becomes 10
- __sync_fetch_and_add(&n, 20); // n becomes 30
- __sync_sub_and_fetch(&n, 15); // n becomes 15
- __sync_bool_compare_and_swap(&n, 15, 201); // n becomes 201
- __sync_fetch_and_and(&n, 200); // n becomes 200
- return (n == 200) ? 0 : -1;
+ // 32-bit
+ __sync_add_and_fetch(&n_32, 10); // n becomes 10
+ __sync_fetch_and_add(&n_32, 20); // n becomes 30
+ __sync_sub_and_fetch(&n_32, 15); // n becomes 15
+ __sync_bool_compare_and_swap(&n_32, 15, 201); // n becomes 201
+ __sync_fetch_and_and(&n_32, 200); // n becomes 200
+ if (n_32 != 200) return -1;
+
+ // 64-bit
+ __sync_add_and_fetch(&n_64, 10); // n becomes 10
+ __sync_fetch_and_add(&n_64, 20); // n becomes 30
+ __sync_sub_and_fetch(&n_64, 15); // n becomes 15
+ __sync_bool_compare_and_swap(&n_64, 15, 201); // n becomes 201
+ __sync_fetch_and_and(&n_64, 200); // n becomes 200
+ if (n_64 != 200) return -1;
+
+ // seems to be okay.
+ return 0;
]])],
[
- AC_DEFINE(HAVE_ATOMIC_OPS,1,[Define to 1 if you have __sync_add_and_fetch() and such])
- AC_MSG_RESULT(yes)
+ squid_cv_gnu_atomics=yes
],[
- AC_MSG_RESULT(no)
-],[ AC_MSG_RESULT(cross-compiler cant tell)
+ squid_cv_gnu_atomics=no
])
+])
+SQUID_DEFINE_BOOL(HAVE_ATOMIC_OPS,${squid_cv_gnu_atomics:=yes},[Define to 1 if you have GCC __sync_add_and_fetch() and such])
AC_ARG_ENABLE(debug-cbdata,
AS_HELP_STRING([--enable-debug-cbdata],
with_mit_krb5=yes
esac
])
+AH_TEMPLATE(USE_APPLE_KRB5,[Apple Kerberos support is available])
AH_TEMPLATE(USE_MIT_KRB5,[MIT Kerberos support is available])
AH_TEMPLATE(USE_SOLARIS_KRB5,[Solaris Kerberos support is available])
krb5confpath="`dirname $ac_cv_path_krb5_config`"
ac_heimdal="`$ac_cv_path_krb5_config --version 2>/dev/null | grep -c -i heimdal`"
ac_solaris="`$ac_cv_path_krb5_config --version 2>/dev/null | grep -c -i solaris`"
+ ac_apple="`$ac_cv_path_krb5_config --vendor 2>/dev/null | grep -c -i apple`"
if test $ac_heimdal -gt 0 ; then
with_heimdal_krb5=yes
ac_with_krb5_count=1
with_solaris_krb5=yes
ac_with_krb5_count=1
fi
- if test $ac_heimdal -eq 0 && test $ac_solaris -eq 0 ; then
+ if test $ac_apple -gt 0 ; then
+ with_apple_krb5=yes
+ ac_with_krb5_count=1
+ fi
+ if test $ac_heimdal -eq 0 && test $ac_solaris -eq 0 && test $ac_apple -eq 0; then
with_mit_krb5=yes
ac_with_krb5_count=1
fi
fi
fi
-if test "x$with_mit_krb5" = "xyes"; then
+if test "x$with_mit_krb5" = "xyes" || test "x$with_apple_krb5" = "xyes" ; then
SQUID_STATE_SAVE([squid_krb5_save])
LIBS="$LIBS $LIB_KRB5_PATH"
])
if test "x$LIB_KRB5_LIBS" != "x"; then
+ if test "x$with_apple_krb5" = "xyes" ; then
+ AC_DEFINE(USE_APPLE_KRB5,1,[Apple Kerberos support is available])
+ KRB5_FLAVOUR="Apple"
+ else
+ AC_DEFINE(USE_MIT_KRB5,1,[MIT Kerberos support is available])
+ KRB5_FLAVOUR="MIT"
+ fi
KRB5LIBS="$LIB_KRB5_PATH $LIB_KRB5_LIBS $KRB5LIBS"
KRB5INCS="$LIB_KRB5_CFLAGS"
- AC_DEFINE(USE_MIT_KRB5,1,[MIT Kerberos support is available])
- KRB5_FLAVOUR="MIT"
# check for other specific broken implementations
CXXFLAGS="$CXXFLAGS $KRB5INCS"
## Please see the COPYING and CONTRIBUTORS files for details.
##
-all: release-3.6.html
+all: release-4.html
-DOC= release-3.6
+DOC= release-4
$(DOC).ps: $(DOC).sgml
linuxdoc -B latex -o ps $(DOC)
<!doctype linuxdoc system>
<article>
-<title>Squid 3.5.2 release notes</title>
+<title>Squid 3.5.3 release notes</title>
<author>Squid Developers</author>
<abstract>
<sect>Notice
<p>
-The Squid Team are pleased to announce the release of Squid-3.5.2.
+The Squid Team are pleased to announce the release of Squid-3.5.3.
This new release is available for download from <url url="http://www.squid-cache.org/Versions/v3/3.5/"> or the
<url url="http://www.squid-cache.org/Download/http-mirrors.html" name="mirrors">.
for the HTTP transaction so far.
<p>New type <em>at_step</em> to match the current SSL-Bump processing step.
Never matches and should not be used outside of <em>ssl_bump</em>.
+ <p>New types <em>ssl::server_name</em> and <em>ssl::server_name_regex</em>
+ to match server name from various sources (CONNECT authority name,
+ TLS SNI domain, or X.509 certificate Subject Name).
<tag>auth_param</tag>
<p>New parameter <em>key_extras</em> to send additional parameters to
<HTML>
<HEAD>
<META NAME="GENERATOR" CONTENT="LinuxDoc-Tools 0.9.69">
- <TITLE>Squid 3.6.0.0 release notes</TITLE>
+ <TITLE>Squid 4.0.0 release notes</TITLE>
</HEAD>
<BODY>
-<H1>Squid 3.6.0.0 release notes</H1>
+<H1>Squid 4.0.0 release notes</H1>
<H2>Squid Developers</H2>
<HR>
-<EM>This document contains the release notes for version 3.6 of Squid.
+<EM>This document contains the release notes for version 4 of Squid.
Squid is a WWW Cache application developed by the National Laboratory
for Applied Network Research and members of the Web Caching community.</EM>
<HR>
<UL>
<LI><A NAME="toc1.1">1.1</A> <A HREF="#ss1.1">Known issues</A>
-<LI><A NAME="toc1.2">1.2</A> <A HREF="#ss1.2">Changes since earlier releases of Squid-3.6</A>
+<LI><A NAME="toc1.2">1.2</A> <A HREF="#ss1.2">Changes since earlier releases of Squid-4</A>
</UL>
<P>
<H2><A NAME="toc2">2.</A> <A HREF="#s2">Major new features since Squid-3.5</A></H2>
<UL>
<LI><A NAME="toc2.1">2.1</A> <A HREF="#ss2.1">Configurable helper queue size</A>
+<LI><A NAME="toc2.2">2.2</A> <A HREF="#ss2.2">Helper concurrency channels changes</A>
+<LI><A NAME="toc2.3">2.3</A> <A HREF="#ss2.3">SSLv2 support removal</A>
+<LI><A NAME="toc2.4">2.4</A> <A HREF="#ss2.4">MSNT-multi-domain helper removal</A>
</UL>
<P>
<H2><A NAME="toc3">3.</A> <A HREF="#s3">Changes to squid.conf since Squid-3.5</A></H2>
<HR>
<H2><A NAME="s1">1.</A> <A HREF="#toc1">Notice</A></H2>
-<P>The Squid Team are pleased to announce the release of Squid-3.6.0.0 for testing.</P>
+<P>The Squid Team are pleased to announce the release of Squid-4.0.0 for testing.</P>
<P>This new release is available for download from
-<A HREF="http://www.squid-cache.org/Versions/v3/3.6/">http://www.squid-cache.org/Versions/v3/3.6/</A> or the
-<A HREF="http://www.squid-cache.org/Mirrors/http-mirrors.html">mirrors</A>.</P>
+<A HREF="http://www.squid-cache.org/Versions/v4/">http://www.squid-cache.org/Versions/v4/</A> or the
+<A HREF="http://www.squid-cache.org/Download/http-mirrors.html">mirrors</A>.</P>
<P>While this release is not deemed ready for production use, we believe it is ready for wider testing by the community.</P>
</H2>
<P>Although this release is deemed good enough for use in many setups, please note the existence of
-<A HREF="http://bugs.squid-cache.org/buglist.cgi?query_format=advanced&product=Squid&bug_status=UNCONFIRMED&bug_status=NEW&bug_status=ASSIGNED&bug_status=REOPENED&version=3.6">open bugs against Squid-3.6</A>.</P>
+<A HREF="http://bugs.squid-cache.org/buglist.cgi?query_format=advanced&product=Squid&bug_status=UNCONFIRMED&bug_status=NEW&bug_status=ASSIGNED&bug_status=REOPENED&version=4">open bugs against Squid-4</A>.</P>
-<H2><A NAME="ss1.2">1.2</A> <A HREF="#toc1.2">Changes since earlier releases of Squid-3.6</A>
+<H2><A NAME="ss1.2">1.2</A> <A HREF="#toc1.2">Changes since earlier releases of Squid-4</A>
</H2>
-<P>The 3.6 change history can be
-<A HREF="http://www.squid-cache.org/Versions/v3/3.6/changesets/">viewed here</A>.</P>
+<P>The Squid-4 change history can be
+<A HREF="http://www.squid-cache.org/Versions/v4/changesets/">viewed here</A>.</P>
<H2><A NAME="s2">2.</A> <A HREF="#toc2">Major new features since Squid-3.5</A></H2>
-<P>Squid 3.6 represents a new feature release above 3.5.</P>
+<P>Squid 4 represents a new feature release above 3.5.</P>
<P>The most important of these new features are:
<UL>
-<LI>BLAH</LI>
+<LI>Helper concurrency channels changes</LI>
+<LI>Configurable helper queue size</LI>
+<LI>SSLv2 support removal</LI>
+<LI>MSNT-multi-domain helper removal</LI>
</UL>
</P>
<P>Most user-facing changes are reflected in squid.conf (see below).</P>
<P>The new queue-size=N option to helpers configuration, allows users
to configure the maximum number of queued requests to busy helpers.</P>
+<H2><A NAME="ss2.2">2.2</A> <A HREF="#toc2.2">Helper concurrency channels changes</A>
+</H2>
+
+<P> helper-mux.pl we have been distributing for the past few years to
+encourage use of concurrency is no longer compatible with Squid. If
+used it will spawn up to 2^64 helpers and DoS the Squid server.</P>
+
+<P> Helpers utilizing arrays to handle fixed amounts of concurrency
+channels MUST be re-written to use queues and capable of handling a
+64-bit int as index or they will be vulnerable to buffer overrun and
+arbitrary memory accesses.</P>
+
+<P> 32-bit helpers need re-writing to handle the concurrency channel ID
+as a 64-bit integer value. If not updated they will cause proxies to
+return unexpected results or timeout once crossing the 32-bit wrap
+boundary. Leading to undefined behaviour in the client HTTP traffic.</P>
+
+<H2><A NAME="ss2.3">2.3</A> <A HREF="#toc2.3">SSLv2 support removal</A>
+</H2>
+
+<P>Details in
+<A HREF="https://tools.ietf.org/html/rfc6176">RFC 6176</A></P>
+
+<P>SSLv2 is not fit for purpose. Squid no longer supports being configured with
+any settings regarding this protocol. That includes settings manually disabling
+its use since it is now forced to disable by default. Also settings enabling
+various client/server workarounds specific to SSLv2 are removed.</P>
+
+
+<H2><A NAME="ss2.4">2.4</A> <A HREF="#toc2.4">MSNT-multi-domain helper removal</A>
+</H2>
+
+<P>The <EM>basic_msnt_multi_domain_auth</EM> helper has been removed. The
+<EM>basic_smb_lm_auth</EM> helper performs the same actions without extra
+Perl and Samba dependencies.</P>
+
+
<H2><A NAME="s3">3.</A> <A HREF="#toc3">Changes to squid.conf since Squid-3.5</A></H2>
<P>There have been changes to Squid's configuration file since Squid-3.5.</P>
<P>
<DL>
+<DT><B>tls_outgoing_options</B><DD>
+<P>New tag to define TLS security context options for outgoing
+connections. For example to HTTPS servers.</P>
+
+<DT><B>url_rewrite_timeout</B><DD>
+<P>Squid times active requests to redirector. This option sets
+the timeout value and the Squid reaction to a timed out
+request.</P>
</DL>
</P>
<P>
<DL>
-<DT><B> auth_param </B><DD>
-<P> New parameter <EM>queue-size=</EM> to set the maximum number
+<DT><B>auth_param</B><DD>
+<P>New parameter <EM>queue-size=</EM> to set the maximum number
of queued requests.</P>
-<DT><B>external_acl_type</B><DD>
+<DT><B>cache_peer</B><DD>
+<P>All <EM>ssloption=</EM> and <EM>sslversion=</EM> values for
+SSLv2 configuration or disabling have been removed.</P>
+<P>Manual squid.conf update may be required on upgrade.</P>
-<DT><B></B><DD>
-<P> New parameter <EM>queue-size=</EM> to set the maximum number
+<DT><B>external_acl_type</B><DD>
+<P>New parameter <EM>queue-size=</EM> to set the maximum number
of queued requests.</P>
-<DT><B>url_rewrite_children</B><DD>
+<DT><B>http_port</B><DD>
+<P>All <EM>version=</EM> <EM>option=</EM> values for SSLv2
+configuration or disabling have been removed.</P>
+<P>Manual squid.conf update may be required on upgrade.</P>
-<DT><B></B><DD>
-<P> New parameter <EM>queue-size=</EM> to set the maximum number
-of queued requests.</P>
+<DT><B>https_port</B><DD>
+<P>All <EM>version=</EM> <EM>option=</EM> values for SSLv2
+configuration or disabling have been removed.</P>
+<P>Manual squid.conf update may be required on upgrade.</P>
<DT><B>sslcrtd_children</B><DD>
-<P> New parameter <EM>queue-size=</EM> to set the maximum number
+<P>New parameter <EM>queue-size=</EM> to set the maximum number
of queued requests.</P>
<DT><B>sslcrtvalidator_children</B><DD>
-<P> New parameter <EM>queue-size=</EM> to set the maximum number
+<P>New parameter <EM>queue-size=</EM> to set the maximum number
of queued requests.</P>
+
+<DT><B>sslproxy_options</B><DD>
+<P>All values for SSLv2 configuration or disabling have been removed.</P>
+<P>Manual squid.conf update may be required on upgrade.</P>
+
+<DT><B>sslproxy_version</B><DD>
+<P>Value '2' for SSLv2-only operation is no longer supported.</P>
+
+<DT><B>url_rewrite_children</B><DD>
+<P>New parameter <EM>queue-size=</EM> to set the maximum number
+of queued requests.</P>
+
</DL>
</P>
<P>
<DL>
+<DT><B>cache_peer_domain</B><DD>
+<P>Superceded by <EM>cache_peer_access</EM>. Use dstdomain ACL
+in the access control list to restrict domains requested.</P>
+
+<DT><B>refresh_pattern</B><DD>
+<P>Option <EM>ignore-auth</EM> removed. Its original intent was
+to improve caching. HTTP/1.1 permits caching of authenticated
+messages under conditions which Squid does check for and obey.</P>
+
+<DT><B>sslproxy_cafile</B><DD>
+<P>Replaced by <EM>tls_outgoing_options cafile=</EM>.</P>
+
+<DT><B>sslproxy_capath</B><DD>
+<P>Replaced by <EM>tls_outgoing_options capath=</EM>.</P>
+
+<DT><B>sslproxy_cipher</B><DD>
+<P>Replaced by <EM>tls_outgoing_options cipher=</EM>.</P>
+
+<DT><B>sslproxy_client_certificate</B><DD>
+<P>Replaced by <EM>tls_outgoing_options cert=</EM>.</P>
+
+<DT><B>sslproxy_client_key</B><DD>
+<P>Replaced by <EM>tls_outgoing_options key=</EM>.</P>
+
+<DT><B>sslproxy_flags</B><DD>
+<P>Replaced by <EM>tls_outgoing_options flags=</EM>.</P>
+
+<DT><B>sslproxy_options</B><DD>
+<P>Replaced by <EM>tls_outgoing_options options=</EM>.</P>
+
+<DT><B>sslproxy_version</B><DD>
+<P>Replaced by <EM>tls_outgoing_options version=</EM>.</P>
</DL>
</P>
<P>
<DL>
+<DT><B>--enable-auth-basic</B><DD>
+<P>The <EM>MSNT-multi-domain</EM> helper has been removed.</P>
</DL>
</P>
<H2><A NAME="s5">5.</A> <A HREF="#toc5">Regressions since Squid-2.7</A></H2>
-<P>Some squid.conf options which were available in Squid-2.7 are not yet available in Squid-3.6</P>
+<P>Some squid.conf options which were available in Squid-2.7 are not yet available in Squid-4</P>
<P>If you need something to do then porting one of these from Squid-2 to Squid-3 is most welcome.</P>
<!doctype linuxdoc system>
<article>
-<title>Squid 3.6.0.0 release notes</title>
+<title>Squid 4.0.0 release notes</title>
<author>Squid Developers</author>
<abstract>
-This document contains the release notes for version 3.6 of Squid.
+This document contains the release notes for version 4 of Squid.
Squid is a WWW Cache application developed by the National Laboratory
for Applied Network Research and members of the Web Caching community.
</abstract>
<sect>Notice
<p>
-The Squid Team are pleased to announce the release of Squid-3.6.0.0 for testing.
+The Squid Team are pleased to announce the release of Squid-4.0.0 for testing.
-This new release is available for download from <url url="http://www.squid-cache.org/Versions/v3/3.6/"> or the
+This new release is available for download from <url url="http://www.squid-cache.org/Versions/v4/"> or the
<url url="http://www.squid-cache.org/Download/http-mirrors.html" name="mirrors">.
<p>While this release is not deemed ready for production use, we believe it is ready for wider testing by the community.
<sect1>Known issues
<p>
Although this release is deemed good enough for use in many setups, please note the existence of
-<url url="http://bugs.squid-cache.org/buglist.cgi?query_format=advanced&product=Squid&bug_status=UNCONFIRMED&bug_status=NEW&bug_status=ASSIGNED&bug_status=REOPENED&version=3.6" name="open bugs against Squid-3.6">.
+<url url="http://bugs.squid-cache.org/buglist.cgi?query_format=advanced&product=Squid&bug_status=UNCONFIRMED&bug_status=NEW&bug_status=ASSIGNED&bug_status=REOPENED&version=4" name="open bugs against Squid-4">.
-<sect1>Changes since earlier releases of Squid-3.6
+<sect1>Changes since earlier releases of Squid-4
<p>
-The 3.6 change history can be <url url="http://www.squid-cache.org/Versions/v3/3.6/changesets/" name="viewed here">.
+The Squid-4 change history can be <url url="http://www.squid-cache.org/Versions/v4/changesets/" name="viewed here">.
<sect>Major new features since Squid-3.5
-<p>Squid 3.6 represents a new feature release above 3.5.
+<p>Squid 4 represents a new feature release above 3.5.
<p>The most important of these new features are:
<itemize>
SSLv2 configuration or disabling have been removed.
<p>Manual squid.conf update may be required on upgrade.
- <tag>external_acl_type<tag>
+ <tag>external_acl_type</tag>
<p>New parameter <em>queue-size=</em> to set the maximum number
of queued requests.
<tag>sslproxy_version</tag>
<p>Value '2' for SSLv2-only operation is no longer supported.
- <tag>url_rewrite_children<tag>
+ <tag>url_rewrite_children</tag>
<p>New parameter <em>queue-size=</em> to set the maximum number
of queued requests.
<sect>Regressions since Squid-2.7
-<p>Some squid.conf options which were available in Squid-2.7 are not yet available in Squid-3.6
+<p>Some squid.conf options which were available in Squid-2.7 are not yet available in Squid-4
<p>If you need something to do then porting one of these from Squid-2 to Squid-3 is most welcome.
rfc7235.txt
Hypertext Transfer Protocol (HTTP/1.1): Authentication
-rfc7238.txt
- The Hypertext Transfer Protocol Status Code 308 (Permanent Redirect)
-
rfc7239.txt
Forwarded HTTP Extension
Details the Forwarded: header replacement for X-Forwarded-For
and other X-Forwarded-* variants
+
+rfc7538.txt
+ The Hypertext Transfer Protocol Status Code 308 (Permanent Redirect)
Internet Engineering Task Force (IETF) J. Reschke
-Request for Comments: 7238 greenbytes
-Category: Experimental June 2014
+Request for Comments: 7538 greenbytes
+Obsoletes: 7238 April 2015
+Category: Standards Track
ISSN: 2070-1721
Status of This Memo
- This document is not an Internet Standards Track specification; it is
- published for examination, experimental implementation, and
- evaluation.
+ This is an Internet Standards Track document.
- This document defines an Experimental Protocol for the Internet
- community. This document is a product of the Internet Engineering
- Task Force (IETF). It represents the consensus of the IETF
- community. It has received public review and has been approved for
- publication by the Internet Engineering Steering Group (IESG). Not
- all documents approved by the IESG are a candidate for any level of
- Internet Standard; see Section 2 of RFC 5741.
+ This document is a product of the Internet Engineering Task Force
+ (IETF). It represents the consensus of the IETF community. It has
+ received public review and has been approved for publication by the
+ Internet Engineering Steering Group (IESG). Further information on
+ Internet Standards is available in Section 2 of RFC 5741.
Information about the current status of this document, any errata,
and how to provide feedback on it may be obtained at
- http://www.rfc-editor.org/info/rfc7238.
+ http://www.rfc-editor.org/info/rfc7538.
Copyright Notice
- Copyright (c) 2014 IETF Trust and the persons identified as the
+ Copyright (c) 2015 IETF Trust and the persons identified as the
document authors. All rights reserved.
This document is subject to BCP 78 and the IETF Trust's Legal
-Reschke Experimental [Page 1]
+
+
+
+Reschke Standards Track [Page 1]
\f
-RFC 7238 HTTP Status Code 308 June 2014
+RFC 7538 HTTP Status Code 308 April 2015
Table of Contents
- 1. Introduction . . . . . . . . . . . . . . . . . . . . . . . . . 2
- 2. Notational Conventions . . . . . . . . . . . . . . . . . . . . 2
- 3. 308 Permanent Redirect . . . . . . . . . . . . . . . . . . . . 2
- 4. Deployment Considerations . . . . . . . . . . . . . . . . . . . 3
- 5. Security Considerations . . . . . . . . . . . . . . . . . . . . 4
- 6. IANA Considerations . . . . . . . . . . . . . . . . . . . . . . 4
- 7. Acknowledgements . . . . . . . . . . . . . . . . . . . . . . . 5
- 8. References . . . . . . . . . . . . . . . . . . . . . . . . . . 5
- 8.1. Normative References . . . . . . . . . . . . . . . . . . . 5
- 8.2. Informative References . . . . . . . . . . . . . . . . . . 5
+ 1. Introduction . . . . . . . . . . . . . . . . . . . . . . . . 2
+ 2. Notational Conventions . . . . . . . . . . . . . . . . . . . 2
+ 3. 308 Permanent Redirect . . . . . . . . . . . . . . . . . . . 3
+ 4. Deployment Considerations . . . . . . . . . . . . . . . . . . 3
+ 5. Security Considerations . . . . . . . . . . . . . . . . . . . 4
+ 6. IANA Considerations . . . . . . . . . . . . . . . . . . . . . 5
+ 7. References . . . . . . . . . . . . . . . . . . . . . . . . . 5
+ 7.1. Normative References . . . . . . . . . . . . . . . . . . 5
+ 7.2. Informative References . . . . . . . . . . . . . . . . . 5
+ Acknowledgements . . . . . . . . . . . . . . . . . . . . . . . . 6
+ Author's Address . . . . . . . . . . . . . . . . . . . . . . . . 6
1. Introduction
| method from POST to GET | | |
+-------------------------------------------+-----------+-----------+
- Section 6.4.7 of [RFC7231] states that HTTP does not define a
- permanent variant of status code 307; this specification adds the
- status code 308, defining this missing variant (Section 3).
+ Section 6.4.7 of [RFC7231] states that it does not define a permanent
+ variant of status code 307; this specification adds the status code
+ 308, defining this missing variant (Section 3).
+
+ This specification contains no technical changes from the
+ Experimental RFC 7238, which it obsoletes.
2. Notational Conventions
"SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this
document are to be interpreted as described in [RFC2119].
-3. 308 Permanent Redirect
- The 308 (Permanent Redirect) status code indicates that the target
- resource has been assigned a new permanent URI and any future
- references to this resource ought to use one of the enclosed URIs.
-Reschke Experimental [Page 2]
+Reschke Standards Track [Page 2]
\f
-RFC 7238 HTTP Status Code 308 June 2014
+RFC 7538 HTTP Status Code 308 April 2015
+
+3. 308 Permanent Redirect
+ The 308 (Permanent Redirect) status code indicates that the target
+ resource has been assigned a new permanent URI and any future
+ references to this resource ought to use one of the enclosed URIs.
Clients with link editing capabilities ought to automatically re-link
references to the effective request URI (Section 5.5 of [RFC7230]) to
one or more of the new references sent by the server, where possible.
4. Deployment Considerations
Section 6 of [RFC7231] requires recipients to treat unknown 3xx
- status codes the same way as status code 300 Multiple Choices
+ status codes the same way as status code 300 (Multiple Choices)
([RFC7231], Section 6.4.1). Thus, servers will not be able to rely
on automatic redirection happening similar to status codes 301, 302,
or 307.
- Therefore, initial use of status code 308 will be restricted to cases
- where the server has sufficient confidence in the client's
- understanding the new code or when a fallback to the semantics of
- status code 300 is not problematic. Server implementers are advised
- not to vary the status code based on characteristics of the request,
- such as the User-Agent header field ("User-Agent Sniffing") -- doing
- so usually results in code that is both hard to maintain and hard to
- debug and would also require special attention to caching (i.e.,
- setting a "Vary" response header field, as defined in Section 7.1.4
- of [RFC7231]).
+ Therefore, the use of status code 308 is restricted to cases where
+ the server has sufficient confidence in the client's understanding
+ the new code or when a fallback to the semantics of status code 300
+ is not problematic. Server implementers are advised not to vary the
+ status code based on characteristics of the request, such as the
+ User-Agent header field ("User-Agent Sniffing") -- doing so usually
+ results in code that is both hard to maintain and hard to debug and
+ would also require special attention to caching (i.e., setting a
+ "Vary" response header field, as defined in Section 7.1.4 of
+ [RFC7231]).
- Note that many existing HTML-based user agents will emulate a refresh
- when encountering an HTML <meta> refresh directive ([HTML]). This
- can be used as another fallback. For example:
- Client request:
- GET / HTTP/1.1
- Host: example.com
-Reschke Experimental [Page 3]
+
+Reschke Standards Track [Page 3]
\f
-RFC 7238 HTTP Status Code 308 June 2014
+RFC 7538 HTTP Status Code 308 April 2015
+
+
+ Note that many existing HTML-based user agents will emulate a refresh
+ when encountering an HTML <meta> refresh directive ([HTML],
+ Section 4.2.5.3). This can be used as another fallback. For
+ example:
+
+ Client request:
+
+ GET / HTTP/1.1
+ Host: example.com
Server response:
HTTP/1.1 308 Permanent Redirect
Content-Type: text/html; charset=UTF-8
Location: http://example.com/new
- Content-Length: 454
+ Content-Length: 356
- <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
- "http://www.w3.org/TR/html4/strict.dtd">
+ <!DOCTYPE HTML>
<html>
<head>
<title>Permanent Redirect</title>
All security considerations that apply to HTTP redirects apply to the
308 status code as well (see Section 9 of [RFC7231]).
-6. IANA Considerations
-
- The registration below has been added to the "Hypertext Transfer
- Protocol (HTTP) Status Code Registry" (defined in Section 8.2 of
- [RFC7231] and located at
- <http://www.iana.org/assignments/http-status-codes>):
-
- +-------+--------------------+---------------------------------+
- | Value | Description | Reference |
- +-------+--------------------+---------------------------------+
- | 308 | Permanent Redirect | Section 3 of this specification |
- +-------+--------------------+---------------------------------+
-
+ Unsecured communication over the Internet is subject to man-in-the-
+ middle modification of messages, including changing status codes or
+ redirect targets. Use of Transport Layer Security (TLS) is one way
+ to mitigate those attacks. See Section 9 of [RFC7230] for related
+ attacks on authority and message integrity.
-
-
-Reschke Experimental [Page 4]
+Reschke Standards Track [Page 4]
\f
-RFC 7238 HTTP Status Code 308 June 2014
+RFC 7538 HTTP Status Code 308 April 2015
-7. Acknowledgements
+6. IANA Considerations
- The definition for the new status code 308 reuses text from the
- HTTP/1.1 definitions of status codes 301 and 307.
+ The "Hypertext Transfer Protocol (HTTP) Status Code Registry"
+ (defined in Section 8.2 of [RFC7231] and located at
+ <http://www.iana.org/assignments/http-status-codes>) has been updated
+ to reference this specification.
- Furthermore, thanks to Ben Campbell, Cyrus Daboo, Eran Hammer-Lahav,
- Bjoern Hoehrmann, Subramanian Moonesamy, Peter Saint-Andre, and
- Robert Sparks for feedback on this document.
+ +-------+--------------------+----------------------------------+
+ | Value | Description | Reference |
+ +-------+--------------------+----------------------------------+
+ | 308 | Permanent Redirect | Section 3 of this specification |
+ +-------+--------------------+----------------------------------+
-8. References
+7. References
-8.1. Normative References
+7.1. Normative References
[RFC2119] Bradner, S., "Key words for use in RFCs to Indicate
- Requirement Levels", BCP 14, RFC 2119, March 1997.
+ Requirement Levels", BCP 14, RFC 2119, March 1997,
+ <http://www.rfc-editor.org/info/rfc2119>.
[RFC3986] Berners-Lee, T., Fielding, R., and L. Masinter, "Uniform
- Resource Identifier (URI): Generic Syntax", STD 66,
- RFC 3986, January 2005.
+ Resource Identifier (URI): Generic Syntax", STD 66, RFC
+ 3986, January 2005,
+ <http://www.rfc-editor.org/info/rfc3986>.
[RFC7230] Fielding, R., Ed. and J. Reschke, Ed., "Hypertext Transfer
- Protocol (HTTP/1.1): Message Syntax and Routing",
- RFC 7230, June 2014.
+ Protocol (HTTP/1.1): Message Syntax and Routing", RFC
+ 7230, June 2014, <http://www.rfc-editor.org/info/rfc7230>.
[RFC7231] Fielding, R., Ed. and J. Reschke, Ed., "Hypertext Transfer
Protocol (HTTP/1.1): Semantics and Content", RFC 7231,
- June 2014.
+ June 2014, <http://www.rfc-editor.org/info/rfc7231>.
[RFC7234] Fielding, R., Ed., Nottingham, M., Ed., and J. Reschke,
Ed., "Hypertext Transfer Protocol (HTTP/1.1): Caching",
- RFC 7234, June 2014.
-
-8.2. Informative References
-
- [HTML] Raggett, D., Le Hors, A., and I. Jacobs, "HTML 4.01
- Specification", W3C Recommendation REC-html401-19991224,
- December 1999,
- <http://www.w3.org/TR/1999/REC-html401-19991224>.
-
- Latest version available at
- <http://www.w3.org/TR/html401>.
+ RFC 7234, June 2014,
+ <http://www.rfc-editor.org/info/rfc7234>.
+7.2. Informative References
+ [HTML] Hickson, I., Berjon, R., Faulkner, S., Leithead, T., Doyle
+ Navara, E., O'Connor, E., and S. Pfeiffer, "HTML5", W3C
+ Recommendation REC-html5-20141028, October 2014,
+ <http://www.w3.org/TR/2014/REC-html5-20141028/>.
+ Latest version available at <http://www.w3.org/TR/html5/>.
+Reschke Standards Track [Page 5]
+\f
+RFC 7538 HTTP Status Code 308 April 2015
+Acknowledgements
-Reschke Experimental [Page 5]
-\f
-RFC 7238 HTTP Status Code 308 June 2014
+ The definition for the new status code 308 reuses text from the
+ HTTP/1.1 definitions of status codes 301 and 307.
+ Furthermore, thanks to Ben Campbell, Cyrus Daboo, Adrian Farrell,
+ Eran Hammer-Lahav, Bjoern Hoehrmann, Barry Leiba, Subramanian
+ Moonesamy, Kathleen Moriarty, Peter Saint-Andre, Robert Sparks, and
+ Roy Fielding for feedback on this document.
Author's Address
-
-
-
-
-
-
-
-
-
-
-Reschke Experimental [Page 6]
+Reschke Standards Track [Page 6]
\f
==============================================================================
-SQUID Internet Object Cache http://www.squid-cache.org
---------------------------------------------------------
-
- Squid is the result of efforts by numerous individuals from the
- Internet community. Development is led by Duane Wessels of the
- National Laboratory for Applied Network Research and funded by
- the National Science Foundation.
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program 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 General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
- MA 02110-1301, USA.
-
-Squid is derived from the ``cached'' software from the ARPA-funded
-Harvest research project. The Harvest home page is
-http://harvest.cs.colorado.edu/.
-
-Squid is originally derived from the Harvest Information Discovery and
-Access System.
+ * Copyright (C) 1996-2015 The Squid Software Foundation and contributors
+ *
+ * Squid software is distributed under GPLv2+ license and includes
+ * contributions from numerous individuals and organizations.
+ * Please see the COPYING and CONTRIBUTORS files for details.
==============================================================================
AC_MSG_ERROR([Basic auth requested but auth disabled])
fi
#define list of modules to build
+auto_auth_basic_modules=no
if test "x$enable_auth_basic" = "xyes" ; then
SQUID_LOOK_FOR_MODULES([$srcdir/helpers/basic_auth],[enable_auth_basic])
+ auto_auth_basic_modules=yes
fi
#handle the "none" special case
if test "x$enable_auth_basic" = "xnone" ; then
if test -d "$srcdir/helpers/basic_auth/$helper"; then
if test "$BUILD_HELPER" != "$helper"; then
- AC_MSG_NOTICE([Basic auth helper $helper ... found but cannot be built])
+ if test "x$auto_auth_basic_modules" = "xyes"; then
+ AC_MSG_NOTICE([Basic auth helper $helper ... found but cannot be built])
+ else
+ AC_MSG_ERROR([Basic auth helper $helper ... found but cannot be built])
+ fi
else
BASIC_AUTH_HELPERS="$BASIC_AUTH_HELPERS $BUILD_HELPER"
fi
$(COMPAT_LIB) \
$(LDAPLIB) \
$(LBERLIB) \
+ $(NETTLELIB) \
$(CRYPTLIB) \
$(SSLLIB) \
$(XTRA_LIBS)
## Please see the COPYING and CONTRIBUTORS files for details.
##
-AC_CHECK_HEADERS([ldap.h winldap.h],[BUILD_HELPER="LDAP"])
+AC_CHECK_HEADERS([ldap.h winldap.h],[BUILD_HELPER="eDirectory"])
AC_MSG_ERROR([Digest auth requested but auth disabled])
fi
#define list of modules to build
+auto_auth_digest_modules=no
if test "x$enable_auth_digest" = "xyes" ; then
SQUID_LOOK_FOR_MODULES([$srcdir/helpers/digest_auth],[enable_auth_digest])
+ auto_auth_digest_modules=yes
fi
#handle the "none" special case
if test "x$enable_auth_digest" = "xnone" ; then
if test -d "$srcdir/helpers/digest_auth/$helper"; then
if test "$BUILD_HELPER" != "$helper"; then
- AC_MSG_NOTICE([Digest auth helper $helper ... found but cannot be built])
+ if test "x$auto_auth_digest_modules" = "xyes"; then
+ AC_MSG_NOTICE([Digest auth helper $helper ... found but cannot be built])
+ else
+ AC_MSG_ERROR([Digest auth helper $helper ... found but cannot be built])
+ fi
else
DIGEST_AUTH_HELPERS="$DIGEST_AUTH_HELPERS $BUILD_HELPER"
fi
if test "x$with_krb5" == "xyes"; then
BUILD_HELPER="kerberos_ldap_group"
+ if test "x$with_apple_krb5" = "xyes" ; then
+ AC_CHECK_LIB(resolv, [main], [XTRA_LIBS="$XTRA_LIBS -lresolv"],[
+ AC_MSG_ERROR([library 'resolv' is required for Apple Kerberos])
+ ])
+ fi
SQUID_CHECK_SASL
fi
#include <cstring>
+#if USE_APPLE_KRB5
+#define KERBEROS_APPLE_DEPRECATED(x)
+#endif
+
#if HAVE_KRB5_H
#if HAVE_BROKEN_SOLARIS_KRB5_H
#warn "Warning! You have a broken Solaris <krb5.h> system header"
void *params)
{
struct ldap_creds *cp = (struct ldap_creds *) params;
+ struct berval cred;
+ if (cp->pw) {
+ cred.bv_val=cp->pw;
+ cred.bv_len=strlen(cp->pw);
+ }
whop = whop;
credp = credp;
methodp = methodp;
freeit = freeit;
- return ldap_bind_s(ld, cp->dn, cp->pw, LDAP_AUTH_SIMPLE);
+ return ldap_sasl_bind_s(ld, cp->dn, LDAP_SASL_SIMPLE, &cred, NULL, NULL, NULL);
}
#elif HAVE_LDAP_REBIND_PROC
#if HAVE_SASL_H || HAVE_SASL_SASL_H || HAVE_SASL_DARWIN
void *params)
{
struct ldap_creds *cp = (struct ldap_creds *) params;
- return ldap_bind_s(ld, cp->dn, cp->pw, LDAP_AUTH_SIMPLE);
+ struct berval cred;
+ if (cp->pw) {
+ cred.bv_val=cp->pw;
+ cred.bv_len=strlen(cp->pw);
+ }
+ return ldap_sasl_bind_s(ld, cp->dn, LDAP_SASL_SIMPLE, &cred, NULL, NULL, NULL);
}
#elif HAVE_LDAP_REBIND_FUNCTION
void *params)
{
struct ldap_creds *cp = (struct ldap_creds *) params;
+ struct berval cred;
+ if (cp->pw) {
+ cred.bv_val=cp->pw;
+ cred.bv_len=strlen(cp->pw);
+ }
whop = whop;
credp = credp;
methodp = methodp;
freeit = freeit;
- return ldap_bind_s(ld, cp->dn, cp->pw, LDAP_AUTH_SIMPLE);
+ return ldap_sasl_bind_s(ld, cp->dn, LDAP_SASL_SIMPLE, &cred, NULL, NULL, NULL);
}
#else
#error "No rebind functione defined"
static LDAP_REBIND_PROC ldap_sasl_rebind;
static int
-ldap_sasl_rebind(LDAP *ld, LDAP_CONST char *, ber_tag_t, ber_int_t, void *params)
+ldap_sasl_rebind(LDAP *ld, LDAP_CONST char *, ber_tag_t request, ber_int_t msgid, void *params)
{
struct ldap_creds *cp = (struct ldap_creds *) params;
return tool_sasl_bind(ld, cp->dn, cp->pw);
static LDAP_REBIND_PROC ldap_simple_rebind;
static int
-ldap_simple_rebind(LDAP * ld, LDAP_CONST char *, ber_tag_t, ber_int_t, void *params)
+ldap_simple_rebind(LDAP *ld, LDAP_CONST char *, ber_tag_t request, ber_int_t msgid, void *params)
{
struct ldap_creds *cp = (struct ldap_creds *) params;
- return ldap_bind_s(ld, cp->dn, cp->pw, LDAP_AUTH_SIMPLE);
+ struct berval cred;
+ if (cp->pw) {
+ cred.bv_val=cp->pw;
+ cred.bv_len=strlen(cp->pw);
+ }
+ return ldap_sasl_bind_s(ld, cp->dn, LDAP_SASL_SIMPLE, &cred, NULL, NULL, NULL);
}
#endif
xfree(ldapuri);
if (rc != LDAP_SUCCESS) {
error((char *) "%s| %s: ERROR: Error while initialising connection to ldap server: %s\n", LogTime(), PROGRAM, ldap_err2string(rc));
- ldap_unbind(ld);
+ ldap_unbind_ext(ld,NULL,NULL);
ld = NULL;
return NULL;
}
rc = ldap_set_defaults(ld);
if (rc != LDAP_SUCCESS) {
error((char *) "%s| %s: ERROR: Error while setting default options for ldap server: %s\n", LogTime(), PROGRAM, ldap_err2string(rc));
- ldap_unbind(ld);
+ ldap_unbind_ext(ld, NULL, NULL);
ld = NULL;
return NULL;
}
rc = ldap_set_ssl_defaults(margs);
if (rc != LDAP_SUCCESS) {
error((char *) "%s| %s: ERROR: Error while setting SSL default options for ldap server: %s\n", LogTime(), PROGRAM, ldap_err2string(rc));
- ldap_unbind(ld);
+ ldap_unbind_ext(ld, NULL, NULL);
ld = NULL;
return NULL;
}
rc = ldap_start_tls_s(ld, NULL, NULL);
if (rc != LDAP_SUCCESS) {
error((char *) "%s| %s: ERROR: Error while setting start_tls for ldap server: %s\n", LogTime(), PROGRAM, ldap_err2string(rc));
- ldap_unbind(ld);
+ ldap_unbind_ext(ld, NULL, NULL);
ld = NULL;
url = (LDAPURLDesc *) xmalloc(sizeof(*url));
memset(url, 0, sizeof(*url));
xfree(ldapuri);
if (rc != LDAP_SUCCESS) {
error((char *) "%s| %s: ERROR: Error while initialising connection to ldap server: %s\n", LogTime(), PROGRAM, ldap_err2string(rc));
- ldap_unbind(ld);
+ ldap_unbind_ext(ld, NULL, NULL);
ld = NULL;
return NULL;
}
rc = ldap_set_defaults(ld);
if (rc != LDAP_SUCCESS) {
error((char *) "%s| %s: ERROR: Error while setting default options for ldap server: %s\n", LogTime(), PROGRAM, ldap_err2string(rc));
- ldap_unbind(ld);
+ ldap_unbind_ext(ld, NULL, NULL);
ld = NULL;
return NULL;
}
ld = ldapssl_init(host, port, 1);
if (!ld) {
error((char *) "%s| %s: ERROR: Error while setting SSL for ldap server: %s\n", LogTime(), PROGRAM, ldapssl_err2string(rc));
- ldap_unbind(ld);
+ ldap_unbind_ext(ld, NULL, NULL);
ld = NULL;
return NULL;
}
rc = ldap_set_defaults(ld);
if (rc != LDAP_SUCCESS) {
error((char *) "%s| %s: ERROR: Error while setting default options for ldap server: %s\n", LogTime(), PROGRAM, ldap_err2string(rc));
- ldap_unbind(ld);
+ ldap_unbind_ext(ld, NULL, NULL);
ld = NULL;
return NULL;
}
rc = tool_sasl_bind(ld, bindp, margs->ssl);
if (rc != LDAP_SUCCESS) {
error((char *) "%s| %s: ERROR: Error while binding to ldap server with SASL/GSSAPI: %s\n", LogTime(), PROGRAM, ldap_err2string(rc));
- ldap_unbind(ld);
+ ldap_unbind_ext(ld, NULL, NULL);
ld = NULL;
continue;
}
break;
}
#else
- ldap_unbind(ld);
+ ldap_unbind_ext(ld, NULL, NULL);
ld = NULL;
error((char *) "%s| %s: ERROR: SASL not supported on system\n", LogTime(), PROGRAM);
continue;
nhosts = get_hostname_list(&hlist, 0, host);
xfree(host);
for (size_t i = 0; i < nhosts; ++i) {
-
+ struct berval cred;
+ if (margs->lpass) {
+ cred.bv_val=margs->lpass;
+ cred.bv_len=strlen(margs->lpass);
+ }
ld = tool_ldap_open(margs, hlist[i].host, port, ssl);
if (!ld)
continue;
*/
debug((char *) "%s| %s: DEBUG: Bind to ldap server with Username/Password\n", LogTime(), PROGRAM);
- rc = ldap_simple_bind_s(ld, margs->luser, margs->lpass);
+ rc = ldap_sasl_bind_s(ld, margs->luser, LDAP_SASL_SIMPLE, &cred, NULL, NULL, NULL);
if (rc != LDAP_SUCCESS) {
error((char *) "%s| %s: ERROR: Error while binding to ldap server with Username/Password: %s\n", LogTime(), PROGRAM, ldap_err2string(rc));
- ldap_unbind(ld);
+ ldap_unbind_ext(ld, NULL, NULL);
ld = NULL;
continue;
}
rc = check_AD(margs, ld);
if (rc != LDAP_SUCCESS) {
error((char *) "%s| %s: ERROR: Error determining ldap server type: %s\n", LogTime(), PROGRAM, ldap_err2string(rc));
- ldap_unbind(ld);
+ ldap_unbind_ext(ld, NULL, NULL);
ld = NULL;
retval = 0;
goto cleanup;
if (rc != LDAP_SUCCESS) {
error((char *) "%s| %s: ERROR: Error searching ldap server: %s\n", LogTime(), PROGRAM, ldap_err2string(rc));
- ldap_unbind(ld);
+ ldap_unbind_ext(ld, NULL, NULL);
ld = NULL;
retval = 0;
goto cleanup;
ldap_msgfree(res);
} else if (ldap_count_entries(ld, res) == 0 && margs->AD) {
ldap_msgfree(res);
- ldap_unbind(ld);
+ ldap_unbind_ext(ld, NULL, NULL);
ld = NULL;
retval = 0;
goto cleanup;
safe_free(attr_value);
}
}
- rc = ldap_unbind(ld);
+ rc = ldap_unbind_ext(ld, NULL, NULL);
ld = NULL;
if (rc != LDAP_SUCCESS) {
error((char *) "%s| %s: ERROR: Error unbind ldap server: %s\n", LogTime(), PROGRAM, ldap_err2string(rc));
# FIXME: de-duplicate $enable_external_acl_helpers list containing double entries.
#define list of modules to build
+auto_ext_acl_modules=no
if test "x${enable_external_acl_helpers:=yes}" = "xyes" ;then
SQUID_LOOK_FOR_MODULES([$srcdir/helpers/external_acl],[enable_external_acl_helpers])
+ auto_ext_acl_modules=yes
fi
if test "x$enable_external_acl_helpers" = "xnone" ; then
enable_external_acl_helpers=""
if test -d "$srcdir/helpers/external_acl/$helper"; then
if test "$BUILD_HELPER" != "$helper"; then
- AC_MSG_NOTICE([external acl helper $helper ... found but cannot be built])
+ if test "x$auto_ext_acl_modules" = "xyes"; then
+ AC_MSG_NOTICE([external acl helper $helper ... found but cannot be built])
+ else
+ AC_MSG_ERROR([external acl helper $helper ... found but cannot be built])
+ fi
else
EXTERNAL_ACL_HELPERS="$EXTERNAL_ACL_HELPERS $BUILD_HELPER"
fi
# FIXME: de-duplicate $enable_log_daemon_helpers list containing double entries.
#define list of modules to build
+auto_logdaemon_modules=no
if test "x${enable_log_daemon_helpers:=yes}" = "xyes" ;then
enable_log_daemon_helpers=""
SQUID_LOOK_FOR_MODULES([$srcdir/helpers/log_daemon],[enable_log_daemon_helpers])
+ auto_logdaemon_modules=yes
fi
if test "x$enable_log_daemon_helpers" = "xnone" ; then
enable_log_daemon_helpers=""
if test -d "$srcdir/helpers/log_daemon/$helper"; then
if test "$BUILD_HELPER" != "$helper"; then
- AC_MSG_NOTICE([Log daemon helper $helper ... found but cannot be built])
+ if test "x$auto_logdaemon_modules" = "xyes"; then
+ AC_MSG_NOTICE([Log daemon helper $helper ... found but cannot be built])
+ else
+ AC_MSG_ERROR([Log daemon helper $helper ... found but cannot be built])
+ fi
else
LOG_DAEMON_HELPERS="$LOG_DAEMON_HELPERS $BUILD_HELPER"
fi
#include "base64.h"
#include "util.h"
+#if USE_APPLE_KRB5
+#define KERBEROS_APPLE_DEPRECATED(x)
+#define GSSKRB_APPLE_DEPRECATED(x)
+#endif
+
#if HAVE_KRB5_H
#if HAVE_BROKEN_SOLARIS_KRB5_H
#warn "Warning! You have a broken Solaris <krb5.h> system header"
uint32_t pointer;
} RPC_UNICODE_STRING;
-int check_k5_err(krb5_context context, const char *msg, krb5_error_code code);
void align(int n);
void getustr(RPC_UNICODE_STRING *string);
char **getgids(char **Rids, uint32_t GroupIds, uint32_t GroupCount);
#else
#define HAVE_PAC_SUPPORT 0
#endif
+int check_k5_err(krb5_context context, const char *msg, krb5_error_code code);
krb5_kt_list *kt_list);
#endif /* HAVE_KRB5_MEMORY_KEYTAB */
-#if HAVE_PAC_SUPPORT || HAVE_KRB5_MEMORY_KEYTAB
int
check_k5_err(krb5_context context, const char *function, krb5_error_code code)
{
}
return code;
}
-#endif
char *
gethost_name(void)
if (!check_k5_err(context, "krb5_init_context", ret)) {
krb5_kt_default_name(context, default_keytab, MAXPATHLEN);
}
- keytab_name = default_keytab;
+ keytab_name = xstrdup(default_keytab);
krb5_free_context(context);
} else
keytab_name = xstrdup(keytab_name_env);
#include "squid.h"
#if HAVE_GSSAPI
+#if USE_APPLE_KRB5
+#define GSSKRB_APPLE_DEPRECATED(x)
+#endif
#include <cerrno>
#include <cstring>
AC_MSG_ERROR([Negotiate auth requested but auth disabled])
fi
#define list of modules to build
+auto_auth_negotiate_modules=no
if test "x$enable_auth_negotiate" = "xyes" ; then
SQUID_LOOK_FOR_MODULES([$srcdir/helpers/negotiate_auth],[enable_auth_negotiate])
+ auto_auth_negotiate_modules=yes
fi
#handle the "none" special case
if test "x$enable_auth_negotiate" = "xnone" ; then
if test -d "$srcdir/helpers/negotiate_auth/$helper"; then
if test "$BUILD_HELPER" != "$helper"; then
- AC_MSG_NOTICE([Negotiate auth helper $helper ... found but cannot be built])
+ if test "x$auto_auth_negotiate_modules" = "xyes"; then
+ AC_MSG_NOTICE([Negotiate auth helper $helper ... found but cannot be built])
+ else
+ AC_MSG_ERROR([Negotiate auth helper $helper ... found but cannot be built])
+ fi
else
NEGOTIATE_AUTH_HELPERS="$NEGOTIATE_AUTH_HELPERS $BUILD_HELPER"
fi
#if HAVE_GETOPT_H
#include <getopt.h>
#endif
-#if HAVE_STDINT_H
-#include <stdint.h>
-#endif
-#if HAVE_INTTYPES_H
-#include <inttypes.h>
-#endif
/* A couple of harmless helper macros */
#define SEND(X) {debug("sending '%s' to squid\n",X); printf(X "\n");}
AC_MSG_ERROR([NTLM auth requested but auth disabled])
fi
#define list of modules to build
+auto_auth_ntlm_modules=no
if test "x$enable_auth_ntlm" = "xyes" ; then
SQUID_LOOK_FOR_MODULES([$srcdir/helpers/ntlm_auth],[enable_auth_ntlm])
+ auto_auth_ntlm_modules=yes
fi
#handle the "none" special case
if test "x$enable_auth_ntlm" = "xnone" ; then
if test -d "$srcdir/helpers/ntlm_auth/$helper"; then
if test "$BUILD_HELPER" != "$helper"; then
- AC_MSG_NOTICE([NTLM auth helper $helper ... found but cannot be built])
+ if test "x$auto_auth_ntlm_modules" = "xyes"; then
+ AC_MSG_NOTICE([NTLM auth helper $helper ... found but cannot be built])
+ else
+ AC_MSG_ERROR([NTLM auth helper $helper ... found but cannot be built])
+ fi
else
NTLM_AUTH_HELPERS="$NTLM_AUTH_HELPERS $BUILD_HELPER"
fi
# FIXME: de-duplicate $enable_storeid_rewrite_helpers list containing double entries.
#define list of modules to build
+auto_storeid_modules=no
if test "x${enable_storeid_rewrite_helpers:=yes}" = "xyes" ; then
SQUID_LOOK_FOR_MODULES([$srcdir/helpers/storeid_rewrite],[enable_storeid_rewrite_helpers])
+ auto_storeid_modules=yes
fi
enable_storeid_rewrite_helpers="`echo $enable_storeid_rewrite_helpers| sed -e 's/,/ /g;s/ */ /g'`"
if test -d "$srcdir/helpers/storeid_rewrite/$helper"; then
if test "$BUILD_HELPER" != "$helper"; then
- AC_MSG_NOTICE([Store-ID rewrite helper $helper ... found but cannot be built])
+ if test "x$auto_storeid_modules" = "xyes"; then
+ AC_MSG_NOTICE([Store-ID rewrite helper $helper ... found but cannot be built])
+ else
+ AC_MSG_ERROR([Store-ID rewrite helper $helper ... found but cannot be built])
+ fi
else
STOREID_REWRITE_HELPERS="$STOREID_REWRITE_HELPERS $BUILD_HELPER"
fi
# FIXME: de-duplicate $enable_url_rewrite_helpers list containing double entries.
#define list of modules to build
+auto_urlrewrite_modules=no
if test "x${enable_url_rewrite_helpers:=yes}" = "xyes" ; then
SQUID_LOOK_FOR_MODULES([$srcdir/helpers/url_rewrite],[enable_url_rewrite_helpers])
+ auto_urlrewrite_modules=yes
fi
enable_url_rewrite_helpers="`echo $enable_url_rewrite_helpers| sed -e 's/,/ /g;s/ */ /g'`"
if test -d "$srcdir/helpers/url_rewrite/$helper"; then
if test "$BUILD_HELPER" != "$helper"; then
- AC_MSG_NOTICE([URL rewrite helper $helper ... found but cannot be built])
+ if test "x$auto_urlrewrite_modules" = "xyes"; then
+ AC_MSG_NOTICE([URL rewrite helper $helper ... found but cannot be built])
+ else
+ AC_MSG_ERROR([URL rewrite helper $helper ... found but cannot be built])
+ fi
else
URL_REWRITE_HELPERS="$URL_REWRITE_HELPERS $BUILD_HELPER"
fi
#if USE_OPENSSL
#include "acl/Certificate.h"
#include "acl/CertificateData.h"
+#include "acl/ServerName.h"
#include "acl/SslError.h"
#include "acl/SslErrorData.h"
#endif
ACL::Prototype ACLAtStep::RegistryProtoype(&ACLAtStep::RegistryEntry_, "at_step");
ACLStrategised<Ssl::BumpStep> ACLAtStep::RegistryEntry_(new ACLAtStepData, ACLAtStepStrategy::Instance(), "at_step");
+
+ACL::Prototype ACLServerName::LiteralRegistryProtoype(&ACLServerName::LiteralRegistryEntry_, "ssl::server_name");
+ACLStrategised<char const *> ACLServerName::LiteralRegistryEntry_(new ACLServerNameData, ACLServerNameStrategy::Instance(), "ssl::server_name");
+ACL::Prototype ACLServerName::RegexRegistryProtoype(&ACLServerName::RegexRegistryEntry_, "ssl::server_name_regex");
+ACLFlag ServerNameRegexFlags[] = {ACL_F_REGEX_CASE, ACL_F_END};
+ACLStrategised<char const *> ACLServerName::RegexRegistryEntry_(new ACLRegexData, ACLServerNameStrategy::Instance(), "ssl::server_name_regex", ServerNameRegexFlags);
#endif
#if USE_SQUID_EUI
#include "ssl/PeerConnector.h"
#include "ssl/ServerBump.h"
#include "ssl/support.h"
+#else
+#include "security/EncryptorAnswer.h"
#endif
#include <cerrno>
class FwdStatePeerAnswerDialer: public CallDialer, public Ssl::PeerConnector::CbDialer
{
public:
- typedef void (FwdState::*Method)(Ssl::PeerConnectorAnswer &);
+ typedef void (FwdState::*Method)(Security::EncryptorAnswer &);
FwdStatePeerAnswerDialer(Method method, FwdState *fwd):
method_(method), fwd_(fwd), answer_() {}
}
/* Ssl::PeerConnector::CbDialer API */
- virtual Ssl::PeerConnectorAnswer &answer() { return answer_; }
+ virtual Security::EncryptorAnswer &answer() { return answer_; }
private:
Method method_;
CbcPointer<FwdState> fwd_;
- Ssl::PeerConnectorAnswer answer_;
+ Security::EncryptorAnswer answer_;
};
#endif
}
#endif
- // should reach ConnStateData before the dispatched Client job starts
- CallJobHere1(17, 4, request->clientConnectionManager, ConnStateData,
- ConnStateData::notePeerConnection, serverConnection());
-
- dispatch();
+ // if not encrypting just run the post-connect actions
+ Security::EncryptorAnswer nil;
+ connectedToPeer(nil);
}
-#if USE_OPENSSL
void
-FwdState::connectedToPeer(Ssl::PeerConnectorAnswer &answer)
+FwdState::connectedToPeer(Security::EncryptorAnswer &answer)
{
if (ErrorState *error = answer.error.get()) {
fail(error);
return;
}
+ // should reach ConnStateData before the dispatched Client job starts
+ CallJobHere1(17, 4, request->clientConnectionManager, ConnStateData,
+ ConnStateData::notePeerConnection, serverConnection());
+
dispatch();
}
-#endif
void
FwdState::connectTimeout(int fd)
#include "fde.h"
#include "http/StatusCode.h"
#include "ip/Address.h"
+#include "security/forward.h"
#if USE_OPENSSL
#include "ssl/support.h"
#endif
{
class ErrorDetail;
class CertValidationResponse;
-class PeerConnectorAnswer;
};
#endif
void completed();
void retryOrBail();
ErrorState *makeConnectingError(const err_type type) const;
-#if USE_OPENSSL
- void connectedToPeer(Ssl::PeerConnectorAnswer &answer);
-#endif
+ void connectedToPeer(Security::EncryptorAnswer &answer);
static void RegisterWithCacheManager(void);
/// stops monitoring server connection for closure and updates pconn stats
// zero return means need more data
// positive return is the size of parsed headers
bool
-HttpMsg::parse(MemBuf *buf, bool eof, Http::StatusCode *error)
+HttpMsg::parse(const char *buf, const size_t sz, bool eof, Http::StatusCode *error)
{
assert(error);
*error = Http::scNone;
- // httpMsgParseStep() and debugging require 0-termination, unfortunately
- buf->terminate(); // does not affect content size
-
// find the end of headers
- const size_t hdr_len = headersEnd(buf->content(), buf->contentSize());
+ const size_t hdr_len = headersEnd(buf, sz);
// sanity check the start line to see if this is in fact an HTTP message
if (!sanityCheckStartLine(buf, hdr_len, error)) {
return false;
}
- // TODO: move to httpReplyParseStep()
- if (hdr_len > Config.maxReplyHeaderSize || (hdr_len <= 0 && (size_t)buf->contentSize() > Config.maxReplyHeaderSize)) {
+ if (hdr_len > Config.maxReplyHeaderSize || (hdr_len <= 0 && sz > Config.maxReplyHeaderSize)) {
debugs(58, DBG_IMPORTANT, "HttpMsg::parse: Too large reply header (" << hdr_len << " > " << Config.maxReplyHeaderSize);
*error = Http::scHeaderTooLarge;
return false;
}
if (hdr_len <= 0) {
- debugs(58, 3, "HttpMsg::parse: failed to find end of headers (eof: " << eof << ") in '" << buf->content() << "'");
+ debugs(58, 3, "HttpMsg::parse: failed to find end of headers (eof: " << eof << ") in '" << buf << "'");
if (eof) // iff we have seen the end, this is an error
*error = Http::scInvalidHeader;
return false;
}
- const int res = httpMsgParseStep(buf->content(), buf->contentSize(), eof);
+ const int res = httpMsgParseStep(buf, sz, eof);
if (res < 0) { // error
- debugs(58, 3, "HttpMsg::parse: cannot parse isolated headers in '" << buf->content() << "'");
+ debugs(58, 3, "HttpMsg::parse: cannot parse isolated headers in '" << buf << "'");
*error = Http::scInvalidHeader;
return false;
}
if (res == 0) {
- debugs(58, 2, "HttpMsg::parse: strange, need more data near '" << buf->content() << "'");
+ debugs(58, 2, "HttpMsg::parse: strange, need more data near '" << buf << "'");
*error = Http::scInvalidHeader;
return false; // but this should not happen due to headersEnd() above
}
assert(res > 0);
- debugs(58, 9, "HttpMsg::parse success (" << hdr_len << " bytes) near '" << buf->content() << "'");
+ debugs(58, 9, "HttpMsg::parse success (" << hdr_len << " bytes) near '" << buf << "'");
if (hdr_sz != (int)hdr_len) {
debugs(58, DBG_IMPORTANT, "internal HttpMsg::parse vs. headersEnd error: " <<
// returns true and sets hdr_sz on success
// returns false and sets *error to zero when needs more data
// returns false and sets *error to a positive Http::StatusCode on error
- bool parse(MemBuf *buf, bool eol, Http::StatusCode *error);
+ bool parse(const char *buf, const size_t sz, bool eol, Http::StatusCode *error);
bool parseCharBuf(const char *buf, ssize_t end);
* \retval true Status line has no serious problems.
* \retval false Status line has a serious problem. Correct response is indicated by error.
*/
- virtual bool sanityCheckStartLine(MemBuf *buf, const size_t hdr_len, Http::StatusCode *error) = 0;
+ virtual bool sanityCheckStartLine(const char *buf, const size_t hdr_len, Http::StatusCode *error) = 0;
virtual void packFirstLineInto(Packable * p, bool full_uri) const = 0;
* NP: not all error cases are detected yet. Some are left for detection later in parse.
*/
bool
-HttpReply::sanityCheckStartLine(MemBuf *buf, const size_t hdr_len, Http::StatusCode *error)
+HttpReply::sanityCheckStartLine(const char *buf, const size_t hdr_len, Http::StatusCode *error)
{
// hack warning: using psize instead of size here due to type mismatches with MemBuf.
// content is long enough to possibly hold a reply
// 4 being magic size of a 3-digit number plus space delimiter
- if ( buf->contentSize() < (protoPrefix.psize() + 4) ) {
+ if (hdr_len < (size_t)(protoPrefix.psize() + 4)) {
if (hdr_len > 0) {
- debugs(58, 3, HERE << "Too small reply header (" << hdr_len << " bytes)");
+ debugs(58, 3, "Too small reply header (" << hdr_len << " bytes)");
*error = Http::scInvalidHeader;
}
return false;
int pos;
// catch missing or mismatched protocol identifier
// allow special-case for ICY protocol (non-HTTP identifier) in response to faked HTTP request.
- if (strncmp(buf->content(), "ICY", 3) == 0) {
+ if (strncmp(buf, "ICY", 3) == 0) {
protoPrefix = "ICY";
pos = protoPrefix.psize();
} else {
- if (protoPrefix.cmp(buf->content(), protoPrefix.size()) != 0) {
- debugs(58, 3, "HttpReply::sanityCheckStartLine: missing protocol prefix (" << protoPrefix << ") in '" << buf->content() << "'");
+ if (protoPrefix.cmp(buf, protoPrefix.size()) != 0) {
+ debugs(58, 3, "missing protocol prefix (" << protoPrefix << ") in '" << buf << "'");
*error = Http::scInvalidHeader;
return false;
}
pos = protoPrefix.psize();
// skip arbitrary number of digits and a dot in the verion portion
- while ( pos <= buf->contentSize() && (*(buf->content()+pos) == '.' || xisdigit(*(buf->content()+pos)) ) ) ++pos;
+ while ((size_t)pos <= hdr_len && (*(buf+pos) == '.' || xisdigit(*(buf+pos)) ) ) ++pos;
// catch missing version info
if (pos == protoPrefix.psize()) {
- debugs(58, 3, "HttpReply::sanityCheckStartLine: missing protocol version numbers (ie. " << protoPrefix << "/1.0) in '" << buf->content() << "'");
+ debugs(58, 3, "missing protocol version numbers (ie. " << protoPrefix << "/1.0) in '" << buf << "'");
*error = Http::scInvalidHeader;
return false;
}
}
// skip arbitrary number of spaces...
- while (pos <= buf->contentSize() && (char)*(buf->content()+pos) == ' ') ++pos;
+ while ((size_t)pos <= hdr_len && (char)*(buf+pos) == ' ') ++pos;
- if (pos < buf->contentSize() && !xisdigit(*(buf->content()+pos))) {
- debugs(58, 3, "HttpReply::sanityCheckStartLine: missing or invalid status number in '" << buf->content() << "'");
+ if ((size_t)pos < hdr_len && !xisdigit(*(buf+pos))) {
+ debugs(58, 3, "missing or invalid status number in '" << buf << "'");
*error = Http::scInvalidHeader;
return false;
}
\retval false and sets *error to zero when needs more data
\retval false and sets *error to a positive Http::StatusCode on error
*/
- virtual bool sanityCheckStartLine(MemBuf *buf, const size_t hdr_len, Http::StatusCode *error);
+ virtual bool sanityCheckStartLine(const char *buf, const size_t hdr_len, Http::StatusCode *error);
/** \par public, readable; never update these or their .hdr equivalents directly */
time_t date;
* NP: Other errors are left for detection later in the parse.
*/
bool
-HttpRequest::sanityCheckStartLine(MemBuf *buf, const size_t hdr_len, Http::StatusCode *error)
+HttpRequest::sanityCheckStartLine(const char *buf, const size_t hdr_len, Http::StatusCode *error)
{
// content is long enough to possibly hold a reply
// 2 being magic size of a 1-byte request method plus space delimiter
- if ( buf->contentSize() < 2 ) {
+ if (hdr_len < 2) {
// this is ony a real error if the headers apparently complete.
if (hdr_len > 0) {
debugs(58, 3, HERE << "Too large request header (" << hdr_len << " bytes)");
/* See if the request buffer starts with a non-whitespace HTTP request 'method'. */
HttpRequestMethod m;
- m.HttpRequestMethodXXX(buf->content());
+ m.HttpRequestMethodXXX(buf);
if (m == Http::METHOD_NONE) {
debugs(73, 3, "HttpRequest::sanityCheckStartLine: did not find HTTP request method");
*error = Http::scInvalidHeader;
protected:
virtual void packFirstLineInto(Packable * p, bool full_uri) const;
- virtual bool sanityCheckStartLine(MemBuf *buf, const size_t hdr_len, Http::StatusCode *error);
+ virtual bool sanityCheckStartLine(const char *buf, const size_t hdr_len, Http::StatusCode *error);
virtual void hdrCacheInit();
#include "SquidTime.h"
#if USE_OPENSSL
#include "ssl/PeerConnector.h"
+#else
+#include "security/EncryptorAnswer.h"
#endif
CBDATA_CLASS_INIT(PeerPoolMgr);
#if USE_OPENSSL
/// Gives Ssl::PeerConnector access to Answer in the PeerPoolMgr callback dialer.
-class MyAnswerDialer: public UnaryMemFunT<PeerPoolMgr, Ssl::PeerConnectorAnswer, Ssl::PeerConnectorAnswer&>,
+class MyAnswerDialer: public UnaryMemFunT<PeerPoolMgr, Security::EncryptorAnswer, Security::EncryptorAnswer&>,
public Ssl::PeerConnector::CbDialer
{
public:
MyAnswerDialer(const JobPointer &aJob, Method aMethod):
- UnaryMemFunT<PeerPoolMgr, Ssl::PeerConnectorAnswer, Ssl::PeerConnectorAnswer&>(aJob, aMethod, Ssl::PeerConnectorAnswer()) {}
+ UnaryMemFunT<PeerPoolMgr, Security::EncryptorAnswer, Security::EncryptorAnswer&>(aJob, aMethod, Security::EncryptorAnswer()) {}
/* Ssl::PeerConnector::CbDialer API */
- virtual Ssl::PeerConnectorAnswer &answer() { return arg1; }
+ virtual Security::EncryptorAnswer &answer() { return arg1; }
};
#endif
// push() will trigger a checkpoint()
}
-#if USE_OPENSSL
void
-PeerPoolMgr::handleSecuredPeer(Ssl::PeerConnectorAnswer &answer)
+PeerPoolMgr::handleSecuredPeer(Security::EncryptorAnswer &answer)
{
Must(securer != NULL);
securer = NULL;
// allow the closing connection to fully close before we check again
Checkpoint(this, "conn closure while securing");
}
-#endif
void
PeerPoolMgr::openNewConnection()
#include "base/AsyncJob.h"
#include "comm/forward.h"
+#include "security/forward.h"
class HttpRequest;
class CachePeer;
class CommConnectCbParams;
-#if USE_OPENSSL
-namespace Ssl
-{
-class PeerConnectorAnswer;
-}
-#endif
-
/// Maintains an fixed-size "standby" PconnPool for a single CachePeer.
class PeerPoolMgr: public AsyncJob
{
/// Comm::ConnOpener calls this when done opening a connection for us
void handleOpenedConnection(const CommConnectCbParams ¶ms);
-#if USE_OPENSSL
+
/// Ssl::PeerConnector callback
- void handleSecuredPeer(Ssl::PeerConnectorAnswer &answer);
+ void handleSecuredPeer(Security::EncryptorAnswer &answer);
+
/// called when the connection we are trying to secure is closed by a 3rd party
void handleSecureClosure(const CommCloseCbParams ¶ms);
-#endif
+
/// the final step in connection opening (and, optionally, securing) sequence
void pushNewConnection(const Comm::ConnectionPointer &conn);
// it's available, we're effectively claiming ownership
// of it. If it's not, we need to go away (realloc)
if (store_->canAppend(off_+len_, minSpace)) {
- debugs(24, 7, "not growing");
+ debugs(24, 7, id << " not growing");
return bufEnd();
}
// TODO: we may try to memmove before realloc'ing in order to avoid
n = length();
else
n = min(n, length());
- debugs(24, 8, "consume " << n);
+ debugs(24, 8, id << " consume " << n);
SBuf rv(substr(0, n));
chop(n);
return rv;
void
SBuf::forceSize(size_type newSize)
{
+ debugs(24, 8, id << " force " << (newSize > length() ? "grow" : "shrink") << " to length=" << newSize);
+
Must(store_->LockCount() == 1);
if (newSize > min(maxSize,store_->capacity-off_))
throw SBufTooBigException(__FILE__,__LINE__);
void
SBuf::reAlloc(size_type newsize)
{
- debugs(24, 8, "new size: " << newsize);
+ debugs(24, 8, id << " new size: " << newsize);
if (newsize > maxSize)
throw SBufTooBigException(__FILE__, __LINE__);
MemBlob::Pointer newbuf = new MemBlob(newsize);
store_ = newbuf;
off_ = 0;
++stats.cowSlow;
- debugs(24, 7, "new store capacity: " << store_->capacity);
+ debugs(24, 7, id << " new store capacity: " << store_->capacity);
}
SBuf&
void
SBuf::cow(SBuf::size_type newsize)
{
- debugs(24, 8, "new size:" << newsize);
+ debugs(24, 8, id << " new size:" << newsize);
if (newsize == npos || newsize < length())
newsize = length();
if (store_->LockCount() == 1 && newsize == length()) {
- debugs(24, 8, "no cow needed");
+ debugs(24, 8, id << " no cow needed");
++stats.cowFast;
return;
}
/// create an empty (zero-size) SBuf
SBuf();
SBuf(const SBuf &S);
+#if __cplusplus >= 201103L
SBuf(SBuf&& S) : store_(std::move(S.store_)), off_(S.off_), len_(S.len_) {
++stats.moves;
- S.store_=NULL;
+ S.store_=NULL; //RefCount supports NULL, and S is about to be destructed
S.off_=0;
- S.len_=0; //RefCount supports NULL
+ S.len_=0;
}
+#endif
/** Constructor: import c-style string
*
* Current SBuf will share backing store with the assigned one.
*/
SBuf& operator =(const SBuf & S) {return assign(S);}
+#if __cplusplus >= 201103L
SBuf& operator =(SBuf &&S) {
++stats.moves;
if (this != &S) {
}
return *this;
}
+#endif
/** Import a c-string into a SBuf, copying the data.
*
msg.getPod(mbdata);
}
-static const bool Registered = (Mgr::RegisterAction("sbuf",
- "String-Buffer statistics", &SBufStatsAction::Create, 0 , 1),
- true);
+void
+SBufStatsAction::RegisterWithCacheManager()
+{
+ Mgr::RegisterAction("sbuf", "String-Buffer statistics", &SBufStatsAction::Create, 0 , 1);
+}
public:
/// Mgr::ClassActionCreationHandler for Mgr::RegisterAction()
static Pointer Create(const Mgr::CommandPointer &cmd);
+ static void RegisterWithCacheManager(void);
protected:
explicit SBufStatsAction(const Mgr::CommandPointer &cmd);
#include <cstring>
-#if HAVE_STDINT_H
-#include <stdint.h>
-#else /* HAVE_STDINT_H */
-#ifndef INT_MAX
-#define INT_MAX 1<<31 //hack but a safe bet
-#endif /* INT_MAX */
-#endif /* HAVE_STDINT_H */
-
String::String() : size_(0), len_(0), buf_(NULL)
{
#if DEBUGSTRINGS
char *urlMakeAbsolute(const HttpRequest *, const char *);
char *urlRInternal(const char *host, unsigned short port, const char *dir, const char *name);
char *urlInternal(const char *dir, const char *name);
-int matchDomainName(const char *host, const char *domain);
+
+/**
+ * matchDomainName() compares a hostname (usually extracted from traffic)
+ * with a domainname (usually from an ACL) according to the following rules:
+ *
+ * HOST | DOMAIN | MATCH?
+ * -------------|-------------|------
+ * foo.com | foo.com | YES
+ * .foo.com | foo.com | YES
+ * x.foo.com | foo.com | NO
+ * foo.com | .foo.com | YES
+ * .foo.com | .foo.com | YES
+ * x.foo.com | .foo.com | YES
+ *
+ * We strip leading dots on hosts (but not domains!) so that
+ * ".foo.com" is always the same as "foo.com".
+ *
+ * if honorWildcards is true then the matchDomainName() also accepts
+ * optional wildcards on hostname:
+ *
+ * HOST | DOMAIN | MATCH?
+ * -------------|--------------|-------
+ * *.foo.com | x.foo.com | YES
+ * *.foo.com | .x.foo.com | YES
+ * *.foo.com | .foo.com | YES
+ * *.foo.com | foo.com | NO
+ *
+ * \retval 0 means the host matches the domain
+ * \retval 1 means the host is greater than the domain
+ * \retval -1 means the host is less than the domain
+ */
+int matchDomainName(const char *host, const char *domain, bool honorWildcards = false);
int urlCheckRequest(const HttpRequest *);
int urlDefaultPort(AnyP::ProtocolType p);
char *urlHostname(const char *url);
public:
virtual ~ACLDomainData();
- bool match(char const *);
+ virtual bool match(char const *);
virtual SBufList dump() const;
void parse();
bool empty() const;
Certificate.h \
ServerCertificate.cc \
ServerCertificate.h \
+ ServerName.cc \
+ ServerName.h \
SslError.cc \
SslError.h \
SslErrorData.cc \
--- /dev/null
+/*
+ * Copyright (C) 1996-2015 The Squid Software Foundation and contributors
+ *
+ * Squid software is distributed under GPLv2+ license and includes
+ * contributions from numerous individuals and organizations.
+ * Please see the COPYING and CONTRIBUTORS files for details.
+ */
+
+/* DEBUG: section 28 Access Control */
+
+#include "squid.h"
+#include "acl/Checklist.h"
+#include "acl/DomainData.h"
+#include "acl/RegexData.h"
+#include "acl/ServerName.h"
+#include "client_side.h"
+#include "fde.h"
+#include "HttpRequest.h"
+#include "ipcache.h"
+#include "SquidString.h"
+#include "ssl/bio.h"
+#include "ssl/ServerBump.h"
+#include "ssl/support.h"
+#include "URL.h"
+
+// Compare function for tree search algorithms
+static int
+aclHostDomainCompare( char *const &a, char * const &b)
+{
+ const char *h = static_cast<const char *>(a);
+ const char *d = static_cast<const char *>(b);
+ debugs(28, 7, "Match:" << h << " <> " << d);
+ return matchDomainName(h, d, true);
+}
+
+bool
+ACLServerNameData::match(const char *host)
+{
+ if (host == NULL)
+ return 0;
+
+ debugs(28, 3, "checking '" << host << "'");
+
+ char *h = const_cast<char *>(host);
+ char const * const * result = domains->find(h, aclHostDomainCompare);
+
+ debugs(28, 3, "'" << host << "' " << (result ? "found" : "NOT found"));
+
+ return (result != NULL);
+
+}
+
+ACLData<char const *> *
+ACLServerNameData::clone() const
+{
+ /* Splay trees don't clone yet. */
+ assert (!domains);
+ return new ACLServerNameData;
+}
+
+/// A helper function to be used with Ssl::matchX509CommonNames().
+/// \retval 0 when the name (cn or an alternate name) matches acl data
+/// \retval 1 when the name does not match
+template<class MatchType>
+int
+check_cert_domain( void *check_data, ASN1_STRING *cn_data)
+{
+ char cn[1024];
+ ACLData<MatchType> * data = (ACLData<MatchType> *)check_data;
+
+ if (cn_data->length > (int)sizeof(cn) - 1)
+ return 1; // ignore data that does not fit our buffer
+
+ memcpy(cn, cn_data->data, cn_data->length);
+ cn[cn_data->length] = '\0';
+ debugs(28, 4, "Verifying certificate name/subjectAltName " << cn);
+ if (data->match(cn))
+ return 0;
+ return 1;
+}
+
+int
+ACLServerNameStrategy::match (ACLData<MatchType> * &data, ACLFilledChecklist *checklist, ACLFlags &flags)
+{
+ assert(checklist != NULL && checklist->request != NULL);
+
+ if (checklist->conn() && checklist->conn()->serverBump()) {
+ if (X509 *peer_cert = checklist->conn()->serverBump()->serverCert.get()) {
+ if (Ssl::matchX509CommonNames(peer_cert, (void *)data, check_cert_domain<MatchType>))
+ return 1;
+ }
+ }
+
+ const char *serverName = NULL;
+ if (checklist->conn() && !checklist->conn()->sslCommonName().isEmpty()) {
+ SBuf scn = checklist->conn()->sslCommonName();
+ serverName = scn.c_str();
+ }
+
+ if (serverName == NULL)
+ serverName = checklist->request->GetHost();
+
+ if (serverName && data->match(serverName)) {
+ return 1;
+ }
+
+ return data->match("none");
+}
+
+ACLServerNameStrategy *
+ACLServerNameStrategy::Instance()
+{
+ return &Instance_;
+}
+
+ACLServerNameStrategy ACLServerNameStrategy::Instance_;
+
--- /dev/null
+/*
+ * Copyright (C) 1996-2015 The Squid Software Foundation and contributors
+ *
+ * Squid software is distributed under GPLv2+ license and includes
+ * contributions from numerous individuals and organizations.
+ * Please see the COPYING and CONTRIBUTORS files for details.
+ */
+
+#ifndef SQUID_ACLSERVERNAME_H
+#define SQUID_ACLSERVERNAME_H
+
+#include "acl/Acl.h"
+#include "acl/Checklist.h"
+#include "acl/Data.h"
+#include "acl/DomainData.h"
+#include "acl/Strategised.h"
+
+class ACLServerNameData : public ACLDomainData {
+ MEMPROXY_CLASS(ACLServerNameData);
+public:
+ ACLServerNameData() : ACLDomainData() {}
+ virtual bool match(const char *);
+ virtual ACLData<char const *> *clone() const;
+};
+
+class ACLServerNameStrategy : public ACLStrategy<char const *>
+{
+
+public:
+ virtual int match (ACLData<MatchType> * &, ACLFilledChecklist *, ACLFlags &);
+ static ACLServerNameStrategy *Instance();
+ virtual bool requiresRequest() const {return true;}
+
+ /**
+ * Not implemented to prevent copies of the instance.
+ \par
+ * Not private to prevent brain dead g+++ warnings about
+ * private constructors with no friends
+ */
+ ACLServerNameStrategy(ACLServerNameStrategy const &);
+
+private:
+ static ACLServerNameStrategy Instance_;
+ ACLServerNameStrategy() {}
+
+ ACLServerNameStrategy&operator=(ACLServerNameStrategy const &);
+};
+
+class ACLServerName
+{
+
+private:
+ static ACL::Prototype LiteralRegistryProtoype;
+ static ACLStrategised<char const *> LiteralRegistryEntry_;
+ static ACL::Prototype RegexRegistryProtoype;
+ static ACLStrategised<char const *> RegexRegistryEntry_;
+};
+
+#endif /* SQUID_ACLSERVERNAME_H */
+
void
Adaptation::Ecap::HeaderRep::parse(const Area &buf)
{
- MemBuf mb;
- mb.init();
- mb.append(buf.start, buf.size);
Http::StatusCode error;
- Must(theMessage.parse(&mb, true, &error));
+ Must(theMessage.parse(buf.start, buf.size, true, &error));
}
http_hdr_type
return;
}
- if (readBuf.hasSpace())
+ if (readBuf.spaceSize())
scheduleRead();
else
- debugs(93,3,HERE << "nothing to do because !readBuf.hasSpace()");
+ debugs(93,3,HERE << "nothing to do because !readBuf.spaceSize()");
}
// comm module read a portion of the ICAP response for us
void Adaptation::Icap::ModXact::parseMore()
{
- debugs(93, 5, HERE << "have " << readBuf.contentSize() << " bytes to parse" <<
- status());
- debugs(93, 5, HERE << "\n" << readBuf.content());
+ debugs(93, 5, "have " << readBuf.length() << " bytes to parse" << status());
+ debugs(93, 5, "\n" << readBuf);
if (state.parsingHeaders())
parseHeaders();
// parse the buffer back
Http::StatusCode error = Http::scNone;
- Must(adapted.header->parse(&httpBuf, true, &error));
+ httpBuf.terminate(); // HttpMsg::parse requires nil-terminated buffer
+ Must(adapted.header->parse(httpBuf.content(), httpBuf.contentSize(), true, &error));
if (HttpRequest *r = dynamic_cast<HttpRequest*>(adapted.header))
urlCanonical(r); // parse does not set HttpRequest::canonical
bool Adaptation::Icap::ModXact::parseHead(HttpMsg *head)
{
Must(head);
- debugs(93, 5, HERE << "have " << readBuf.contentSize() << " head bytes to parse" <<
- "; state: " << state.parsing);
+ debugs(93, 5, "have " << readBuf.length() << " head bytes to parse; state: " << state.parsing);
Http::StatusCode error = Http::scNone;
- const bool parsed = head->parse(&readBuf, commEof, &error);
+ // XXX: performance regression. c_str() data copies
+ // XXX: HttpMsg::parse requires a terminated string buffer
+ const char *tmpBuf = readBuf.c_str();
+ const bool parsed = head->parse(tmpBuf, readBuf.length(), commEof, &error);
Must(parsed || !error); // success or need more data
if (!parsed) { // need more data
Must(state.parsing == State::psBody);
Must(bodyParser);
- debugs(93, 5, HERE << "have " << readBuf.contentSize() << " body bytes to parse");
+ debugs(93, 5, "have " << readBuf.length() << " body bytes to parse");
// the parser will throw on errors
BodyPipeCheckout bpc(*adapted.body_pipe);
- const bool parsed = bodyParser->parse(&readBuf, &bpc.buf);
+ // XXX: performance regression. SBuf-convert (or Parser-convert?) the chunked decoder.
+ MemBuf encodedData;
+ encodedData.init();
+ // NP: we must do this instead of pointing encodedData at the SBuf::rawContent
+ // because chunked decoder uses MemBuf::consume, which shuffles buffer bytes around.
+ encodedData.append(readBuf.rawContent(), readBuf.length());
+ const bool parsed = bodyParser->parse(&encodedData, &bpc.buf);
+ // XXX: httpChunkDecoder has consumed from MemBuf.
+ readBuf.consume(readBuf.length() - encodedData.contentSize());
bpc.checkIn();
- debugs(93, 5, HERE << "have " << readBuf.contentSize() << " body bytes after " <<
- "parse; parsed all: " << parsed);
+ debugs(93, 5, "have " << readBuf.length() << " body bytes after parsed all: " << parsed);
replyHttpBodySize += adapted.body_pipe->buf().contentSize();
// TODO: expose BodyPipe::putSize() to make this check simpler and clearer
// XXX: HttpRequest cannot fully parse ICAP Request-Line
Http::StatusCode reqStatus;
- Must(icapRequest->parse(&buf, true, &reqStatus) > 0);
+ buf.terminate(); // HttpMsg::parse requires terminated buffer
+ Must(icapRequest->parse(buf.content(), buf.contentSize(), true, &reqStatus) > 0);
}
void Adaptation::Icap::OptXact::handleCommWrote(size_t size)
bool Adaptation::Icap::OptXact::parseResponse()
{
- debugs(93, 5, HERE << "have " << readBuf.contentSize() << " bytes to parse" <<
- status());
- debugs(93, 5, HERE << "\n" << readBuf.content());
+ debugs(93, 5, "have " << readBuf.length() << " bytes to parse" << status());
+ debugs(93, DBG_DATA, "\n" << readBuf);
HttpReply::Pointer r(new HttpReply);
r->protoPrefix = "ICAP/"; // TODO: make an IcapReply class?
attempts(0),
connection(NULL),
theService(aService),
- commBuf(NULL),
- commBufSize(0),
commEof(false),
reuseConnection(true),
isRetriable(true),
void Adaptation::Icap::Xaction::start()
{
Adaptation::Initiate::start();
-
- readBuf.init(SQUID_TCP_SO_RCVBUF, SQUID_TCP_SO_RCVBUF);
- commBuf = (char*)memAllocBuf(SQUID_TCP_SO_RCVBUF, &commBufSize);
- // make sure maximum readBuf space does not exceed commBuf size
- Must(static_cast<size_t>(readBuf.potentialSpaceSize()) <= commBufSize);
}
static void
{
Must(haveConnection());
Must(!reader);
- Must(readBuf.hasSpace());
+ Must(readBuf.length() < SQUID_TCP_SO_RCVBUF); // will expand later if needed
- /*
- * See comments in Adaptation::Icap::Xaction.h about why we use commBuf
- * here instead of reading directly into readBuf.buf.
- */
typedef CommCbMemFunT<Adaptation::Icap::Xaction, CommIoCbParams> Dialer;
- reader = JobCallback(93, 3,
- Dialer, this, Adaptation::Icap::Xaction::noteCommRead);
-
- comm_read(connection, commBuf, readBuf.spaceSize(), reader);
+ reader = JobCallback(93, 3, Dialer, this, Adaptation::Icap::Xaction::noteCommRead);
+ Comm::Read(connection, reader);
updateTimeout();
}
Must(io.flag == Comm::OK);
- if (!io.size) {
+ // TODO: tune this better to expected message sizes
+ readBuf.reserveCapacity(SQUID_TCP_SO_RCVBUF);
+
+ CommIoCbParams rd(this); // will be expanded with ReadNow results
+ rd.conn = io.conn;
+
+ switch (Comm::ReadNow(rd, readBuf)) {
+ case Comm::INPROGRESS:
+ if (readBuf.isEmpty())
+ debugs(33, 2, io.conn << ": no data to process, " << xstrerr(rd.xerrno));
+ scheduleRead();
+ return;
+
+ case Comm::OK:
+ al.icap.bytesRead += rd.size;
+
+ updateTimeout();
+
+ debugs(93, 3, "read " << rd.size << " bytes");
+
+ disableRetries(); // because pconn did not fail
+
+ /* Continue to process previously read data */
+ break;
+
+ case Comm::ENDFILE: // close detected by 0-byte read
commEof = true;
reuseConnection = false;
mustStop("pconn race");
return;
}
- } else {
-
- al.icap.bytesRead+=io.size;
-
- updateTimeout();
-
- debugs(93, 3, HERE << "read " << io.size << " bytes");
- /*
- * See comments in Adaptation::Icap::Xaction.h about why we use commBuf
- * here instead of reading directly into readBuf.buf.
- */
+ break;
- readBuf.append(commBuf, io.size);
- disableRetries(); // because pconn did not fail
+ // case Comm::COMM_ERROR:
+ default: // no other flags should ever occur
+ debugs(11, 2, io.conn << ": read failure: " << xstrerr(rd.xerrno));
+ mustStop("unknown ICAP I/O read error");
+ return;
}
handleCommRead(io.size);
bool Adaptation::Icap::Xaction::parseHttpMsg(HttpMsg *msg)
{
- debugs(93, 5, HERE << "have " << readBuf.contentSize() << " head bytes to parse");
+ debugs(93, 5, "have " << readBuf.length() << " head bytes to parse");
Http::StatusCode error = Http::scNone;
- const bool parsed = msg->parse(&readBuf, commEof, &error);
+ // XXX: performance regression c_str() data copies
+ const char *buf = readBuf.c_str();
+ const bool parsed = msg->parse(buf, readBuf.length(), commEof, &error);
Must(parsed || !error); // success or need more data
if (!parsed) { // need more data
bool Adaptation::Icap::Xaction::mayReadMore() const
{
return !doneReading() && // will read more data
- readBuf.hasSpace(); // have space for more data
+ readBuf.spaceSize(); // have space for more data
}
bool Adaptation::Icap::Xaction::doneReading() const
closeConnection(); // TODO: rename because we do not always close
- if (!readBuf.isNull())
- readBuf.clean();
-
- if (commBuf)
- memFreeBuf(commBufSize, commBuf);
+ readBuf.clear();
tellQueryAborted();
#include "CommCalls.h"
#include "HttpReply.h"
#include "ipcache.h"
-#include "MemBuf.h"
+#include "SBuf.h"
+
+class MemBuf;
namespace Adaptation
{
Comm::ConnectionPointer connection; ///< ICAP server connection
Adaptation::Icap::ServiceRep::Pointer theService;
- /*
- * We have two read buffers. We would prefer to read directly
- * into the MemBuf, but since comm_read isn't MemBuf-aware, and
- * uses event-delayed callbacks, it leaves the MemBuf in an
- * inconsistent state. There would be data in the buffer, but
- * MemBuf.size won't be updated until the (delayed) callback
- * occurs. To avoid that situation we use a plain buffer
- * (commBuf) and then copy (append) its contents to readBuf in
- * the callback. If comm_read ever becomes MemBuf-aware, we
- * can eliminate commBuf and this extra buffer copy.
- */
- MemBuf readBuf;
- char *commBuf;
- size_t commBufSize;
+ SBuf readBuf;
bool commEof;
bool reuseConnection;
bool isRetriable; ///< can retry on persistent connection failures
/**
* Maximum length (buffer size) for token strings.
*/
-// AYJ: must match re-definition in helpers/negotiate_auth/kerberos/negotiate_kerb_auth.cc
-#define MAX_AUTHTOKEN_LEN 32768
+// XXX: Keep in sync with all others: bzr grep 'define MAX_AUTHTOKEN_LEN'
+#define MAX_AUTHTOKEN_LEN 65535
/**
* Node used to link an IP address to some user credentials
Auth::Negotiate::UserRequest::credentialsStr()
{
static char buf[MAX_AUTHTOKEN_LEN];
+ int printResult = 0;
if (user()->credentials() == Auth::Pending) {
- snprintf(buf, sizeof(buf), "YR %s\n", client_blob); //CHECKME: can ever client_blob be 0 here?
+ printResult = snprintf(buf, sizeof(buf), "YR %s\n", client_blob); //CHECKME: can ever client_blob be 0 here?
} else {
- snprintf(buf, sizeof(buf), "KK %s\n", client_blob);
+ printResult = snprintf(buf, sizeof(buf), "KK %s\n", client_blob);
}
+
+ // truncation is OK because we are used only for logging
+ if (printResult < 0) {
+ debugs(29, 2, "Can not build negotiate authentication credentials.");
+ buf[0] = '\0';
+ } else if (printResult >= (int)sizeof(buf))
+ debugs(29, 2, "Negotiate authentication credentials truncated.");
+
return buf;
}
debugs(29, 8, HERE << "credentials state is '" << user()->credentials() << "'");
const char *keyExtras = helperRequestKeyExtras(request, al);
+ int printResult = 0;
if (user()->credentials() == Auth::Pending) {
if (keyExtras)
- snprintf(buf, sizeof(buf), "YR %s %s\n", client_blob, keyExtras);
+ printResult = snprintf(buf, sizeof(buf), "YR %s %s\n", client_blob, keyExtras);
else
- snprintf(buf, sizeof(buf), "YR %s\n", client_blob); //CHECKME: can ever client_blob be 0 here?
+ printResult = snprintf(buf, sizeof(buf), "YR %s\n", client_blob); //CHECKME: can ever client_blob be 0 here?
} else {
if (keyExtras)
- snprintf(buf, sizeof(buf), "KK %s %s\n", client_blob, keyExtras);
+ printResult = snprintf(buf, sizeof(buf), "KK %s %s\n", client_blob, keyExtras);
else
- snprintf(buf, sizeof(buf), "KK %s\n", client_blob);
+ printResult = snprintf(buf, sizeof(buf), "KK %s\n", client_blob);
+ }
+
+ if (printResult < 0 || printResult >= (int)sizeof(buf)) {
+ if (printResult < 0)
+ debugs(29, DBG_CRITICAL, "ERROR: Can not build negotiate authentication helper request");
+ else
+ debugs(29, DBG_CRITICAL, "ERROR: Negotiate authentication helper request too big for the " << sizeof(buf) << "-byte buffer");
+ handler(data);
+ return;
}
waiting = 1;
Auth::Ntlm::UserRequest::credentialsStr()
{
static char buf[MAX_AUTHTOKEN_LEN];
+ int printResult;
if (user()->credentials() == Auth::Pending) {
- snprintf(buf, sizeof(buf), "YR %s\n", client_blob);
+ printResult = snprintf(buf, sizeof(buf), "YR %s\n", client_blob);
} else {
- snprintf(buf, sizeof(buf), "KK %s\n", client_blob);
+ printResult = snprintf(buf, sizeof(buf), "KK %s\n", client_blob);
}
+
+ // truncation is OK because we are used only for logging
+ if (printResult < 0) {
+ debugs(29, 2, "Can not build ntlm authentication credentials.");
+ buf[0] = '\0';
+ } else if (printResult >= (int)sizeof(buf))
+ debugs(29, 2, "Ntlm authentication credentials truncated.");
+
return buf;
}
debugs(29, 8, HERE << "credentials state is '" << user()->credentials() << "'");
const char *keyExtras = helperRequestKeyExtras(request, al);
+ int printResult = 0;
if (user()->credentials() == Auth::Pending) {
if (keyExtras)
- snprintf(buf, sizeof(buf), "YR %s %s\n", client_blob, keyExtras);
+ printResult = snprintf(buf, sizeof(buf), "YR %s %s\n", client_blob, keyExtras);
else
- snprintf(buf, sizeof(buf), "YR %s\n", client_blob); //CHECKME: can ever client_blob be 0 here?
+ printResult = snprintf(buf, sizeof(buf), "YR %s\n", client_blob); //CHECKME: can ever client_blob be 0 here?
} else {
if (keyExtras)
- snprintf(buf, sizeof(buf), "KK %s %s\n", client_blob, keyExtras);
+ printResult = snprintf(buf, sizeof(buf), "KK %s %s\n", client_blob, keyExtras);
else
- snprintf(buf, sizeof(buf), "KK %s\n", client_blob);
+ printResult = snprintf(buf, sizeof(buf), "KK %s\n", client_blob);
}
waiting = 1;
+ if (printResult < 0 || printResult >= (int)sizeof(buf)) {
+ if (printResult < 0)
+ debugs(29, DBG_CRITICAL, "ERROR: Can not build ntlm authentication helper request");
+ else
+ debugs(29, DBG_CRITICAL, "ERROR: Ntlm authentication helper request too big for the " << sizeof(buf) << "-byte buffer.");
+ handler(data);
+ return;
+ }
+
safe_free(client_blob);
helperStatefulSubmit(ntlmauthenticators, buf, Auth::Ntlm::UserRequest::HandleReply,
new Auth::StateData(this, handler, data), authserver);
#if defined(LOCKCOUNT_DEBUG)
old_debug(0,1)("Incrementing this %p from count %u\n",this,count_);
#endif
+ assert(count_ < UINT32_MAX);
++count_;
}
/// Clear one lock / reference against this object.
/// All locks must be cleared before it may be destroyed.
- unsigned unlock() const {
+ uint32_t unlock() const {
#if defined(LOCKCOUNT_DEBUG)
old_debug(0,1)("Decrementing this %p from count %u\n",this,count_);
#endif
}
/// Inspect the current count of references.
- unsigned LockCount() const { return count_; }
+ uint32_t LockCount() const { return count_; }
private:
- mutable unsigned count_; ///< number of references currently being tracked
+ mutable uint32_t count_; ///< number of references currently being tracked
};
// For clarity we provide some aliases for the tracking mechanisms
reference (p);
}
+#if __cplusplus >= 201103L
RefCount (RefCount &&p) : p_(std::move(p.p_)) {
p.p_=NULL;
}
+#endif
RefCount& operator = (const RefCount& p) {
// DO NOT CHANGE THE ORDER HERE!!!
return *this;
}
+#if __cplusplus >= 201103L
RefCount& operator = (RefCount&& p) {
if (this != &p) {
dereference(p.p_);
}
return *this;
}
+#endif
bool operator !() const { return !p_; }
#include "Store.h"
#include <climits>
+
#if USE_CBDATA_DEBUG
#include <algorithm>
#include <vector>
#endif
#if WITH_VALGRIND
-#define HASHED_CBDATA 1
+#include <map>
#endif
static int cbdataCount = 0;
*/
class cbdata
{
-#if !HASHED_CBDATA
+#if !WITH_VALGRIND
public:
void *operator new(size_t, void *where) {return where;}
/**
/** \todo examine making cbdata templated on this - so we get type
* safe access to data - RBC 20030902 */
public:
-#if HASHED_CBDATA
- hash_link hash; // Must be first
-#endif
-
#if USE_CBDATA_DEBUG
void dump(StoreEntry *)const;
#endif
-
+ cbdata() :
+ valid(0),
+ locks(0),
+#if USE_CBDATA_DEBUG
+ file(NULL),
+ line(0),
+#endif
+ cookie(0),
+ data(NULL)
+ {}
~cbdata();
+
int valid;
int32_t locks;
cbdata_type type;
void check(int) const {assert(cookie == ((long)this ^ Cookie));}
static const long Cookie;
-#if !HASHED_CBDATA
+#if !WITH_VALGRIND
size_t dataSize() const { return sizeof(data);}
static long MakeOffset();
static const long Offset;
+#endif
/* MUST be the last per-instance member */
void *data;
-#endif
-
};
const long cbdata::Cookie((long)0xDEADBEEF);
-#if !HASHED_CBDATA
+#if !WITH_VALGRIND
const long cbdata::Offset(MakeOffset());
long
struct CBDataIndex {
MemAllocator *pool;
- FREE *free_func;
}
*cbdata_index = NULL;
int cbdata_types = 0;
-#if HASHED_CBDATA
-static hash_table *cbdata_htable = NULL;
-
-static int
-cbdata_cmp(const void *p1, const void *p2)
-{
- return (char *) p1 - (char *) p2;
-}
-
-static unsigned int
-cbdata_hash(const void *p, unsigned int mod)
-{
- return ((unsigned long) p >> 8) % mod;
-}
+#if WITH_VALGRIND
+static std::map<const void *, cbdata *> cbdata_htable;
#endif
cbdata::~cbdata()
}
#endif
-
- FREE *free_func = cbdata_index[type].free_func;
-
-#if HASHED_CBDATA
- void *p = hash.key;
-#else
- void *p = &data;
-#endif
-
- if (free_func)
- free_func(p);
}
static void
-cbdataInternalInitType(cbdata_type type, const char *name, int size, FREE * free_func)
+cbdataInternalInitType(cbdata_type type, const char *name, int size)
{
char *label;
assert (type == cbdata_types + 1);
snprintf(label, strlen(name) + 20, "cbdata %s (%d)", name, (int) type);
-#if !HASHED_CBDATA
+#if !WITH_VALGRIND
assert((size_t)cbdata::Offset == (sizeof(cbdata) - ((cbdata *)NULL)->dataSize()));
size += cbdata::Offset;
#endif
cbdata_index[type].pool = memPoolCreate(label, size);
-
- cbdata_index[type].free_func = free_func;
-
-#if HASHED_CBDATA
- if (!cbdata_htable)
- cbdata_htable = hash_create(cbdata_cmp, 1 << 12, cbdata_hash);
-#endif
}
cbdata_type
-cbdataInternalAddType(cbdata_type type, const char *name, int size, FREE * free_func)
+cbdataInternalAddType(cbdata_type type, const char *name, int size)
{
if (type)
return type;
type = (cbdata_type)(cbdata_types + 1);
- cbdataInternalInitType(type, name, size, free_func);
+ cbdataInternalInitType(type, name, size);
return type;
}
/* placement new: the pool alloc gives us cbdata + user type memory space
* and we init it with cbdata at the start of it
*/
-#if HASHED_CBDATA
+#if WITH_VALGRIND
c = new cbdata;
p = cbdata_index[type].pool->alloc();
- c->hash.key = p;
- hash_join(cbdata_htable, &c->hash);
+ c->data = p;
+ cbdata_htable.emplace(p,c);
#else
c = new (cbdata_index[type].pool->alloc()) cbdata;
p = (void *)&c->data;
dlinkDelete(&c->link, &cbdataEntries);
#endif
+#if WITH_VALGRIND
+ cbdata_htable.erase(c->data);
+#if USE_CBDATA_DEBUG
+ debugs(45, 3, "Call delete " << p << " " << file << ":" << line);
+#endif
+ delete c;
+#else
+#if USE_CBDATA_DEBUG
+ debugs(45, 3, "Call cbdata::~cbdata() " << p << " " << file << ":" << line);
+#endif
+
/* This is ugly. But: operator delete doesn't get
* the type parameter, so we can't use that
* to free the memory.
* and it would Just Work. RBC 20030902
*/
cbdata_type theType = c->type;
-#if HASHED_CBDATA
- hash_remove_link(cbdata_htable, &c->hash);
-#if USE_CBDATA_DEBUG
- debugs(45, 3, "Call delete " << p << " " << file << ":" << line);
-#endif
- delete c;
-#else
-#if USE_CBDATA_DEBUG
- debugs(45, 3, "Call cbdata::~cbdata() " << p << " " << file << ":" << line);
-#endif
c->cbdata::~cbdata();
-#endif
cbdata_index[theType].pool->freeOne(p);
+#endif
}
void *
cbdataInternalFree(void *p, const char *file, int line)
{
cbdata *c;
-#if HASHED_CBDATA
- c = (cbdata *) hash_lookup(cbdata_htable, p);
+#if WITH_VALGRIND
+ c = cbdata_htable.at(p);
#else
c = (cbdata *) (((char *) p) - cbdata::Offset);
#endif
if (p == NULL)
return;
-#if HASHED_CBDATA
- c = (cbdata *) hash_lookup(cbdata_htable, p);
+#if WITH_VALGRIND
+ c = cbdata_htable.at(p);
#else
c = (cbdata *) (((char *) p) - cbdata::Offset);
#endif
if (p == NULL)
return;
-#if HASHED_CBDATA
- c = (cbdata *) hash_lookup(cbdata_htable, p);
+#if WITH_VALGRIND
+ c = cbdata_htable.at(p);
#else
c = (cbdata *) (((char *) p) - cbdata::Offset);
#endif
debugs(45, 9, p);
-#if HASHED_CBDATA
- c = (cbdata *) hash_lookup(cbdata_htable, p);
+#if WITH_VALGRIND
+ c = cbdata_htable.at(p);
#else
c = (cbdata *) (((char *) p) - cbdata::Offset);
#endif
void
cbdata::dump(StoreEntry *sentry) const
{
-#if HASHED_CBDATA
- void *p = (void *)hash.key;
+#if WITH_VALGRIND
+ void *p = data;
#else
void *p = (void *)&data;
#endif
MemAllocator *pool = cbdata_index[i].pool;
if (pool) {
-#if HASHED_CBDATA
+#if WITH_VALGRIND
int obj_size = pool->objectSize();
#else
int obj_size = pool->objectSize() - cbdata::Offset;
*
* \note For internal CBDATA use only.
*/
-cbdata_type cbdataInternalAddType(cbdata_type type, const char *label, int size, FREE * free_func);
+cbdata_type cbdataInternalAddType(cbdata_type type, const char *label, int size);
/**
* This needs to be defined FIRST in the class definition.
public: \
void *operator new(size_t size) { \
assert(size == sizeof(type)); \
- if (!CBDATA_##type) CBDATA_##type = cbdataInternalAddType(CBDATA_##type, #type, sizeof(type), NULL); \
+ if (!CBDATA_##type) CBDATA_##type = cbdataInternalAddType(CBDATA_##type, #type, sizeof(type)); \
return (type *)cbdataInternalAlloc(CBDATA_##type,__FILE__,__LINE__); \
} \
void operator delete (void *address) { \
# SslBump1: After getting TCP-level and HTTP CONNECT info.
# SslBump2: After getting SSL Client Hello info.
# SslBump3: After getting SSL Server Hello info.
+
+ acl aclname ssl::server_name .foo.com ...
+ # matches server name obtained from various sources [fast]
+ #
+ # The server name is obtained during Ssl-Bump steps from such sources
+ # as CONNECT request URI, client SNI, and SSL server certificate CN.
+ # During each Ssl-Bump step, Squid may improve its understanding of a
+ # "true server name". Unlike dstdomain, this ACL does not perform
+ # DNS lookups.
+
+ acl aclname ssl::server_name_regex [-i] \.foo\.com ...
+ # regex matches server name obtained from various sources [fast]
ENDIF
acl aclname any-of acl1 acl2 ...
# match any one of the acls [fast or slow]
DEFAULT_DOC: Respond with an error message to unidentifiable traffic
DOC_START
Determines Squid behavior when encountering strange requests at the
- beginning of an accepted TCP connection. This is especially useful in
- interception environments where Squid is likely to see connections for
- unsupported protocols that Squid should either terminate or tunnel at
- TCP level.
+ beginning of an accepted TCP connection or the beginning of a bumped
+ CONNECT tunnel. Controlling Squid reaction to unexpected traffic is
+ especially useful in interception environments where Squid is likely
+ to see connections for unsupported protocols that Squid should either
+ terminate or tunnel at TCP level.
on_unsupported_protocol <action> [!]acl ...
- The first matching action wins.
+ The first matching action wins. Only fast ACLs are supported.
Supported actions are:
for the Squid port that received the request (e.g., HTTP
for connections intercepted at the http_port). This is the
default.
-
- Currently, this directive is ignored for non-intercepted connections
- because Squid cannot know what their intended destination is.
+
+ Squid expects the following traffic patterns:
+
+ http_port: a plain HTTP request
+ https_port: SSL/TLS handshake followed by an [encrypted] HTTP request
+ ftp_port: a plain FTP command (no on_unsupported_protocol support yet!)
+ CONNECT tunnel on http_port: same as https_port
+ CONNECT tunnel on https_port: same as https_port
+
+ Currently, this directive has effect on intercepted connections and
+ bumped tunnels only. Other cases are not supported because Squid
+ cannot know the intended destination of other traffic.
For example:
# define what Squid errors indicate receiving non-HTTP traffic:
RFC2475, and RFC3260.
The TOS/DSCP byte must be exactly that - a octet value 0 - 255, or
- "default" to use whatever default your host has. Note that in
- practice often only multiples of 4 is usable as the two rightmost bits
- have been redefined for use by ECN (RFC 3168 section 23.1).
+ "default" to use whatever default your host has.
+ Note that only multiples of 4 are usable as the two rightmost bits have
+ been redefined for use by ECN (RFC 3168 section 23.1).
+ The squid parser will enforce this by masking away the ECN bits.
Processing proceeds in the order specified, and stops at first fully
matching line.
DEFAULT: none
LOC: Ip::Qos::TheConfig.tosToClient
DOC_START
- Allows you to select a TOS/Diffserv value for packets being transmitted
+ Allows you to select a TOS/DSCP value for packets being transmitted
on the client-side, based on an ACL.
clientside_tos ds-field [!]aclname ...
Note: This feature is incompatible with qos_flows. Any TOS values set here
will be overwritten by TOS values in qos_flows.
+
+ The TOS/DSCP byte must be exactly that - a octet value 0 - 255, or
+ "default" to use whatever default your host has.
+ Note that only multiples of 4 are usable as the two rightmost bits have
+ been redefined for use by ECN (RFC 3168 section 23.1).
+ The squid parser will enforce this by masking away the ECN bits.
+
DOC_END
NAME: tcp_outgoing_mark
know what you're specifying. For more information, see RFC2474,
RFC2475, and RFC3260.
- The TOS/DSCP byte must be exactly that - a octet value 0 - 255. Note that
- in practice often only multiples of 4 is usable as the two rightmost bits
- have been redefined for use by ECN (RFC 3168 section 23.1).
+ The TOS/DSCP byte must be exactly that - a octet value 0 - 255.
+ Note that only multiples of 4 are usable as the two rightmost bits have
+ been redefined for use by ECN (RFC 3168 section 23.1).
+ The squid parser will enforce this by masking away the ECN bits.
Mark values can be any unsigned 32-bit integer value.
debugs(33, 4, HERE << clientConnection << ": reading request...");
- if (!in.maybeMakeSpaceAvailable())
+ // we can only read if there is more than 1 byte of space free
+ if (Config.maxRequestBufferSize - in.buf.length() < 2)
return;
typedef CommCbMemFunT<ConnStateData, CommIoCbParams> Dialer;
debugs(33, 5, "PROXY/1.0 protocol on connection " << clientConnection);
clientConnection->local = originalDest;
clientConnection->remote = originalClient;
- clientConnection->flags ^= COMM_TRANSPARENT; // prevent TPROXY spoofing of this new IP.
+ if ((clientConnection->flags & COMM_TRANSPARENT))
+ clientConnection->flags ^= COMM_TRANSPARENT; // prevent TPROXY spoofing of this new IP.
debugs(33, 5, "PROXY/1.0 upgrade: " << clientConnection);
// repeat fetch ensuring the new client FQDN can be logged
clientConnection->local.port(ntohs(ipu.ipv4_addr.dst_port));
clientConnection->remote = ipu.ipv4_addr.src_addr;
clientConnection->remote.port(ntohs(ipu.ipv4_addr.src_port));
- clientConnection->flags ^= COMM_TRANSPARENT; // prevent TPROXY spoofing of this new IP.
+ if ((clientConnection->flags & COMM_TRANSPARENT))
+ clientConnection->flags ^= COMM_TRANSPARENT; // prevent TPROXY spoofing of this new IP.
break;
case 0x2: // IPv6
clientConnection->local = ipu.ipv6_addr.dst_addr;
clientConnection->local.port(ntohs(ipu.ipv6_addr.dst_port));
clientConnection->remote = ipu.ipv6_addr.src_addr;
clientConnection->remote.port(ntohs(ipu.ipv6_addr.src_port));
- clientConnection->flags ^= COMM_TRANSPARENT; // prevent TPROXY spoofing of this new IP.
+ if ((clientConnection->flags & COMM_TRANSPARENT))
+ clientConnection->flags ^= COMM_TRANSPARENT; // prevent TPROXY spoofing of this new IP.
break;
default: // do nothing
break;
* Plus, it breaks our lame *HalfClosed() detection
*/
+ in.maybeMakeSpaceAvailable();
CommIoCbParams rd(this); // will be expanded with ReadNow results
rd.conn = io.conn;
switch (Comm::ReadNow(rd, in.buf)) {
BodyProducer::start();
HttpControlMsgSink::start();
- // ensure a buffer is present for this connection
- in.maybeMakeSpaceAvailable();
-
if (port->disable_pmtu_discovery != DISABLE_PMTU_OFF &&
(transparent() || port->disable_pmtu_discovery == DISABLE_PMTU_ALWAYS)) {
#if defined(IP_MTU_DISCOVER) && defined(IP_PMTUDISC_DONT)
" has no certificate.");
}
+#if defined(TLSEXT_NAMETYPE_host_name)
+ if (!conn->serverBump()) {
+ // when in bumpClientFirst mode, get the server name from SNI
+ if (const char *server = SSL_get_servername(ssl, TLSEXT_NAMETYPE_host_name))
+ conn->resetSslCommonName(server);
+ }
+#endif
+
conn->readSomeData();
}
* Otherwise, calls switchToHttps to generate a dynamic SSL_CTX.
*/
static void
-httpsEstablish(ConnStateData *connState, SSL_CTX *sslContext, Ssl::BumpMode bumpMode)
+httpsEstablish(ConnStateData *connState, SSL_CTX *sslContext)
{
SSL *ssl = NULL;
assert(connState);
const Comm::ConnectionPointer &details = connState->clientConnection;
- if (sslContext && !(ssl = httpsCreate(details, sslContext)))
+ if (!sslContext || !(ssl = httpsCreate(details, sslContext)))
return;
typedef CommCbMemFunT<ConnStateData, CommTimeoutCbParams> TimeoutDialer;
connState, ConnStateData::requestTimeout);
commSetConnTimeout(details, Config.Timeout.request, timeoutCall);
- if (ssl)
- Comm::SetSelect(details->fd, COMM_SELECT_READ, clientNegotiateSSL, connState, 0);
- else {
- char buf[MAX_IPSTRLEN];
- assert(bumpMode != Ssl::bumpNone && bumpMode != Ssl::bumpEnd);
- HttpRequest::Pointer fakeRequest(new HttpRequest);
- fakeRequest->SetHost(details->local.toStr(buf, sizeof(buf)));
- fakeRequest->port = details->local.port();
- fakeRequest->clientConnectionManager = connState;
- fakeRequest->client_addr = connState->clientConnection->remote;
-#if FOLLOW_X_FORWARDED_FOR
- fakeRequest->indirect_client_addr = connState->clientConnection->remote;
-#endif
- fakeRequest->my_addr = connState->clientConnection->local;
- fakeRequest->flags.interceptTproxy = ((connState->clientConnection->flags & COMM_TRANSPARENT) != 0 ) ;
- fakeRequest->flags.intercepted = ((connState->clientConnection->flags & COMM_INTERCEPTION) != 0);
- fakeRequest->myportname = connState->port->name;
- if (fakeRequest->flags.interceptTproxy) {
- if (Config.accessList.spoof_client_ip) {
- ACLFilledChecklist checklist(Config.accessList.spoof_client_ip, fakeRequest.getRaw(), NULL);
- fakeRequest->flags.spoofClientIp = (checklist.fastCheck() == ACCESS_ALLOWED);
- } else
- fakeRequest->flags.spoofClientIp = true;
- } else
- fakeRequest->flags.spoofClientIp = false;
- debugs(33, 4, HERE << details << " try to generate a Dynamic SSL CTX");
- connState->switchToHttps(fakeRequest.getRaw(), bumpMode);
- }
+ Comm::SetSelect(details->fd, COMM_SELECT_READ, clientNegotiateSSL, connState, 0);
}
/**
return;
} else {
SSL_CTX *sslContext = port->staticSslContext.get();
- httpsEstablish(this, sslContext, Ssl::bumpNone);
+ httpsEstablish(this, sslContext);
}
}
void ConnStateData::buildSslCertGenerationParams(Ssl::CertificateProperties &certProperties)
{
- certProperties.commonName = sslCommonName.size() > 0 ? sslCommonName.termedBuf() : sslConnectHostOrIp.termedBuf();
+ certProperties.commonName = sslCommonName_.isEmpty() ? sslConnectHostOrIp.termedBuf() : sslCommonName_.c_str();
// fake certificate adaptation requires bump-server-first mode
if (!sslServerBump) {
assert(!switchedToHttps_);
sslConnectHostOrIp = request->GetHost();
- sslCommonName = request->GetHost();
+ resetSslCommonName(request->GetHost());
// We are going to read new request
flags.readMore = true;
if (bio->gotHello()) {
if (conn->serverBump()) {
Ssl::Bio::sslFeatures const &features = bio->getFeatures();
- if (!features.serverName.isEmpty())
+ if (!features.serverName.isEmpty()) {
conn->serverBump()->clientSni = features.serverName;
+ conn->resetSslCommonName(features.serverName.c_str());
+ }
}
debugs(83, 5, "I got hello. Start forwarding the request!!! ");
Must(sslServerBump != NULL);
if (Comm::IsConnOpen(serverConnection)) {
- SSL *ssl = fd_table[serverConnection->fd].ssl;
- assert(ssl);
- Ssl::X509_Pointer serverCert(SSL_get_peer_certificate(ssl));
- assert(serverCert.get() != NULL);
- sslCommonName = Ssl::CommonHostName(serverCert.get());
- debugs(33, 5, HERE << "HTTPS server CN: " << sslCommonName <<
- " bumped: " << *serverConnection);
-
pinConnection(serverConnection, NULL, NULL, false);
debugs(33, 5, HERE << "bumped HTTPS server: " << sslConnectHostOrIp);
} else {
debugs(33, 5, HERE << "Error while bumping: " << sslConnectHostOrIp);
- Ip::Address intendedDest;
- intendedDest = sslConnectHostOrIp.termedBuf();
- const bool isConnectRequest = !port->flags.isIntercepted();
-
- // Squid serves its own error page and closes, so we want
- // a CN that causes no additional browser errors. Possible
- // only when bumping CONNECT with a user-typed address.
- if (intendedDest.isAnyAddr() || isConnectRequest)
- sslCommonName = sslConnectHostOrIp;
- else if (sslServerBump->serverCert.get())
- sslCommonName = Ssl::CommonHostName(sslServerBump->serverCert.get());
// copy error detail from bump-server-first request to CONNECT request
if (currentobject != NULL && currentobject->http != NULL && currentobject->http->request)
else
assert(sslServerBump == srvBump);
}
+ const SBuf &sslCommonName() const {return sslCommonName_;}
+ void resetSslCommonName(const char *name) {sslCommonName_ = name;}
/// Fill the certAdaptParams with the required data for certificate adaptation
/// and create the key for storing/retrieve the certificate to/from the cache
void buildSslCertGenerationParams(Ssl::CertificateProperties &certProperties);
bool switchedToHttps_;
/// The SSL server host name appears in CONNECT request or the server ip address for the intercepted requests
String sslConnectHostOrIp; ///< The SSL server host name as passed in the CONNECT request
- String sslCommonName; ///< CN name for SSL certificate generation
+ SBuf sslCommonName_; ///< CN name for SSL certificate generation
String sslBumpCertKey; ///< Key to use to store/retrieve generated certificate
/// HTTPS server cert. fetching state for bump-ssl-server-first
if (bumpMode != Ssl::bumpEnd) {
debugs(85, 5, HERE << "SslBump already decided (" << bumpMode <<
"), " << "ignoring ssl_bump for " << http->getConn());
- http->sslBumpNeed(bumpMode); // for processRequest() to bump if needed
+ if (!http->getConn()->serverBump())
+ http->sslBumpNeed(bumpMode); // for processRequest() to bump if needed and not already bumped
http->al->ssl.bumpMode = bumpMode; // inherited from bumped connection
return false;
}
return commSetConnTimeout(conn, -1, nil);
}
+/**
+ * Connect socket FD to given remote address.
+ * If return value is an error flag (COMM_ERROR, ERR_CONNECT, ERR_PROTOCOL, etc.),
+ * then error code will also be returned in errno.
+ */
int
comm_connect_addr(int sock, const Ip::Address &address)
{
address.getAddrInfo(AI, F->sock_family);
/* Establish connection. */
- errno = 0;
+ int xerrno = 0;
if (!F->flags.called_connect) {
F->flags.called_connect = true;
// Async calls development will fix this.
if (x == 0) {
x = -1;
- errno = EINPROGRESS;
- }
-
- if (x < 0) {
+ xerrno = EINPROGRESS;
+ } else if (x < 0) {
debugs(5,5, "comm_connect_addr: sock=" << sock << ", addrinfo( " <<
" flags=" << AI->ai_flags <<
", family=" << AI->ai_family <<
", &addr=" << AI->ai_addr <<
", addrlen=" << AI->ai_addrlen <<
" )" );
- debugs(5, 9, "connect FD " << sock << ": (" << x << ") " << xstrerror());
+ debugs(5, 9, "connect FD " << sock << ": (" << x << ") " << xstrerr(xerrno));
debugs(14,9, "connecting to: " << address );
}
+
} else {
+ errno = 0;
#if _SQUID_NEWSOS6_
/* Makoto MATSUSHITA <matusita@ics.es.osaka-u.ac.jp> */
+ if (connect(sock, AI->ai_addr, AI->ai_addrlen) < 0)
+ xerrno = errno;
- connect(sock, AI->ai_addr, AI->ai_addrlen);
-
- if (errno == EINVAL) {
+ if (xerrno == EINVAL) {
errlen = sizeof(err);
x = getsockopt(sock, SOL_SOCKET, SO_ERROR, &err, &errlen);
-
if (x >= 0)
- errno = x;
+ xerrno = x;
}
-
#else
errlen = sizeof(err);
-
x = getsockopt(sock, SOL_SOCKET, SO_ERROR, &err, &errlen);
-
if (x == 0)
- errno = err;
+ xerrno = err;
#if _SQUID_SOLARIS_
/*
* connect and just returns EPIPE. Create a fake
* error message for connect. -- fenner@parc.xerox.com
*/
- if (x < 0 && errno == EPIPE)
- errno = ENOTCONN;
-
+ if (x < 0 && xerrno == EPIPE)
+ xerrno = ENOTCONN;
+ else
+ xerrno = errno;
#endif
#endif
-
}
Ip::Address::FreeAddr(AI);
PROF_stop(comm_connect_addr);
- if (errno == 0 || errno == EISCONN)
+ errno = xerrno;
+ if (xerrno == 0 || xerrno == EISCONN)
status = Comm::OK;
- else if (ignoreErrno(errno))
+ else if (ignoreErrno(xerrno))
status = Comm::INPROGRESS;
- else if (errno == EAFNOSUPPORT || errno == EINVAL)
+ else if (xerrno == EAFNOSUPPORT || xerrno == EINVAL)
return Comm::ERR_PROTOCOL;
else
return Comm::COMM_ERROR;
debugs(5, DBG_DATA, "comm_connect_addr: FD " << sock << " connection pending");
}
+ errno = xerrno;
return status;
}
debugs(50, 5, HERE << "FD " << new_socket << " is a new socket");
assert(!isOpen(new_socket));
- fd_open(new_socket, FD_MSGHDR, NULL);
+ fd_open(new_socket, FD_MSGHDR, addr->sun_path);
fdd_table[new_socket].close_file = NULL;
#include <sys/epoll.h>
#endif
-static int kdpfd;
+static int kdpfd = -1;
static int max_poll_time = 1000;
static struct epoll_event *pevents;
fde *F = &fd_table[fd];
int epoll_ctl_type = 0;
- struct epoll_event ev;
assert(fd >= 0);
debugs(5, 5, HERE << "FD " << fd << ", type=" << type <<
", handler=" << handler << ", client_data=" << client_data <<
", timeout=" << timeout);
- if (RUNNING_ON_VALGRIND) {
- /* Keep valgrind happy.. complains about uninitialized bytes otherwise */
- memset(&ev, 0, sizeof(ev));
- }
- ev.events = 0;
+ struct epoll_event ev;
+ memset(&ev, 0, sizeof(ev));
ev.data.fd = fd;
if (!F->flags.open) {
typedef enum {
ERR_DETAIL_NONE,
ERR_DETAIL_START = 100000, // to avoid clashes with most OS error numbers
- ERR_DETAIL_REDIRECTOR_TIMEDOUT, // External redirector request timed-out
- ERR_DETAIL_CLT_REQMOD_ABORT = ERR_DETAIL_START, // client-facing code detected transaction abort
+ ERR_DETAIL_REDIRECTOR_TIMEDOUT = ERR_DETAIL_START, // External redirector request timed-out
+ ERR_DETAIL_CLT_REQMOD_ABORT, // client-facing code detected transaction abort
ERR_DETAIL_CLT_REQMOD_REQ_BODY, // client-facing code detected REQMOD request body adaptation failure
ERR_DETAIL_CLT_REQMOD_RESP_BODY, // client-facing code detected REQMOD satisfaction reply body failure
ERR_DETAIL_SRV_REQMOD_REQ_BODY, // server-facing code detected REQMOD request body abort
case 'm':
if (building_deny_info_url) break;
#if USE_AUTH
- p = auth_user_request->denyMessage("[not available]");
+ if (auth_user_request.getRaw())
+ p = auth_user_request->denyMessage("[not available]");
+ else
+ p = "[not available]";
#else
p = "-";
#endif
fdUpdateBiggest(fd, 1);
- if (desc)
- xstrncpy(F->desc, desc, FD_DESC_SZ);
+ fd_note(fd, desc);
++Number_FD;
}
fd_note(int fd, const char *s)
{
fde *F = &fd_table[fd];
- xstrncpy(F->desc, s, FD_DESC_SZ);
+ if (s)
+ xstrncpy(F->desc, s, FD_DESC_SZ);
+ else
+ *(F->desc) = 0; // ""-string
}
void
namespace Ufs
{
-class RebuildState : public RefCountable
+class RebuildState
{
CBDATA_CLASS(RebuildState);
static EVH RebuildStep;
RebuildState(RefCount<UFSSwapDir> sd);
- ~RebuildState();
+ virtual ~RebuildState();
virtual bool error() const;
virtual bool isDone() const;
* Plus, it breaks our lame *HalfClosed() detection
*/
+ Must(maybeMakeSpaceAvailable(true));
CommIoCbParams rd(this); // will be expanded with ReadNow results
rd.conn = io.conn;
rd.size = entry->bytesWanted(Range<size_t>(0, inBuf.spaceSize()));
case Comm::INPROGRESS:
if (inBuf.isEmpty())
debugs(33, 2, io.conn << ": no data to process, " << xstrerr(rd.xerrno));
+ flags.do_next_read = true;
maybeReadVirginBody();
return;
// case Comm::COMM_ERROR:
default: // no other flags should ever occur
debugs(11, 2, io.conn << ": read failure: " << xstrerr(rd.xerrno));
-
- if (ignoreErrno(rd.xerrno)) {
- flags.do_next_read = true;
- } else {
- ErrorState *err = new ErrorState(ERR_READ_ERROR, Http::scBadGateway, fwd->request);
- err->xerrno = rd.xerrno;
- fwd->fail(err);
- flags.do_next_read = false;
- io.conn->close();
- }
+ ErrorState *err = new ErrorState(ERR_READ_ERROR, Http::scBadGateway, fwd->request);
+ err->xerrno = rd.xerrno;
+ fwd->fail(err);
+ flags.do_next_read = false;
+ io.conn->close();
return;
}
if (!Comm::IsConnOpen(serverConnection) || fd_table[serverConnection->fd].closing())
return;
+ if (!maybeMakeSpaceAvailable(false))
+ return;
+
+ // XXX: get rid of the do_next_read flag
+ // check for the proper reasons preventing read(2)
+ if (!flags.do_next_read)
+ return;
+
+ flags.do_next_read = false;
+
+ // must not already be waiting for read(2) ...
+ assert(!Comm::MonitorsRead(serverConnection->fd));
+
+ // wait for read(2) to be possible.
+ typedef CommCbMemFunT<HttpStateData, CommIoCbParams> Dialer;
+ AsyncCall::Pointer call = JobCallback(11, 5, Dialer, this, HttpStateData::readReply);
+ Comm::Read(serverConnection, call);
+}
+
+bool
+HttpStateData::maybeMakeSpaceAvailable(bool doGrow)
+{
// how much we are allowed to buffer
const int limitBuffer = (flags.headers_parsed ? Config.readAheadGap : Config.maxReplyHeaderSize);
debugs(11, DBG_DATA, "buffer has {" << inBuf << "}");
// Process next response from buffer
processReply();
- return;
+ return false;
}
// how much we want to read
if (!read_size) {
debugs(11, 7, "wont read up to " << read_size << " into buffer (" << inBuf.length() << "/" << inBuf.spaceSize() << ") from " << serverConnection);
- return;
+ return false;
}
+ // just report whether we could grow or not, dont actually do it
+ if (doGrow)
+ return (read_size >= 2);
+
// we may need to grow the buffer
inBuf.reserveSpace(read_size);
debugs(11, 8, (!flags.do_next_read ? "wont" : "may") <<
" read up to " << read_size << " bytes info buf(" << inBuf.length() << "/" << inBuf.spaceSize() <<
") from " << serverConnection);
- // XXX: get rid of the do_next_read flag
- // check for the proper reasons preventing read(2)
- if (!flags.do_next_read)
- return;
-
- flags.do_next_read = false;
-
- // must not already be waiting for read(2) ...
- assert(!Comm::MonitorsRead(serverConnection->fd));
-
- // wait for read(2) to be possible.
- typedef CommCbMemFunT<HttpStateData, CommIoCbParams> Dialer;
- AsyncCall::Pointer call = JobCallback(11, 5, Dialer, this, HttpStateData::readReply);
- Comm::Read(serverConnection, call);
+ return (inBuf.spaceSize() >= 2); // only read if there is 1+ bytes of space available
}
/// called after writing the very last request byte (body, last-chunk, etc)
virtual void abortTransaction(const char *reason); // abnormal termination
virtual bool mayReadVirginReplyBody() const;
+ /**
+ * determine if read buffer can have space made available
+ * for a read.
+ *
+ * \param grow whether to actually expand the buffer
+ *
+ * \return whether the buffer can be grown to provide space
+ * regardless of whether the grow actually happened.
+ */
+ bool maybeMakeSpaceAvailable(bool grow);
+
// consuming request body
virtual void handleMoreRequestBodyAvailable();
virtual void handleRequestBodyProducerAborted();
scNotModified = 304,
scUseProxy = 305,
scTemporaryRedirect = 307,
- scPermanentRedirect = 308, /**< RFC7238 */
+ scPermanentRedirect = 308, /**< RFC7538 */
scBadRequest = 400,
scUnauthorized = 401,
scPaymentRequired = 402,
static const SBuf crlf("\r\n");
while (tok.prefix(p, iso8859Line)) {
- tok.skipOne(CharacterSet::LF); // move tokenizer past the LF
+ if (!tok.skipOne(CharacterSet::LF)) // move tokenizer past the LF
+ break; // error. reached invalid octet or end of buffer insted of an LF ??
// header lines must start with the name (case insensitive)
if (p.substr(0, namelen).caseCmp(name, namelen))
class ResponseParser : public Http1::Parser
{
public:
- ResponseParser() : Parser(), completedStatus_(false) {}
+ ResponseParser() : Parser(), completedStatus_(false), statusCode_(Http::scNone) {}
virtual ~ResponseParser() {}
/* Http::One::Parser API */
if (log->aclList && checklist && checklist->fastCheck(log->aclList) != ACCESS_ALLOWED)
continue;
+ // The special-case "none" type has no logfile object set
+ if (log->type == Log::Format::CLF_NONE)
+ return;
+
if (log->logfile) {
logfileLineStart(log->logfile);
break;
#endif
- case Log::Format::CLF_NONE:
- return; // abort!
-
default:
fatalf("Unknown log format %d\n", log->type);
break;
#include "profiler/Profiler.h"
#include "redirect.h"
#include "refresh.h"
+#include "SBufStatsAction.h"
#include "send-announce.h"
#include "SquidConfig.h"
#include "SquidTime.h"
/* register the modules in the cache manager menus */
cbdataRegisterWithCacheManager();
+ SBufStatsAction::RegisterWithCacheManager();
+
/* These use separate calls so that the comm loops can eventually
* coexist.
*/
}
writePidFile();
+ enter_suid(); // writePidFile() uses leave_suid()
#if defined(_SQUID_LINUX_THREADS_)
squid_signal(SIGQUIT, rotate_logs, 0);
enter_suid();
removePidFile();
+ enter_suid(); // removePidFile() uses leave_suid()
if (TheKids.someSignaled(SIGINT) || TheKids.someSignaled(SIGTERM)) {
syslog(LOG_ALERT, "Exiting due to unexpected forced shutdown");
exit(1);
#if HAVE_CTYPE_H
#include <ctype.h>
#endif
-#if HAVE_STDINT_H
-#include <stdint.h>
-#endif
-#ifndef INT64_MIN
-/* Native 64 bit system without strtoll() */
-#if defined(LONG_MIN) && (SIZEOF_LONG == 8)
-#define INT64_MIN LONG_MIN
-#else
-/* 32 bit system */
-#define INT64_MIN (-9223372036854775807LL-1LL)
-#endif
-#endif
-
-#ifndef INT64_MAX
-/* Native 64 bit system without strtoll() */
-#if defined(LONG_MAX) && (SIZEOF_LONG == 8)
-#define INT64_MAX LONG_MAX
-#else
-/* 32 bit system */
-#define INT64_MAX 9223372036854775807LL
-#endif
-#endif
/// convenience method: consumes up to n bytes, counts, and returns them
SBuf
#include "squid.h"
#if HAVE_KRB5 && HAVE_GSSAPI
+#if USE_APPLE_KRB5
+#define KERBEROS_APPLE_DEPRECATED(x)
+#define GSSKRB_APPLE_DEPRECATED(x)
+#endif
#include "base64.h"
#include "Debug.h"
callback (NULL),
callback_data (NULL),
lastError(NULL),
+ paths(NULL),
servers (NULL),
first_parent_miss(),
closest_parent_miss(),
--- /dev/null
+/*
+ * Copyright (C) 1996-2015 The Squid Software Foundation and contributors
+ *
+ * Squid software is distributed under GPLv2+ license and includes
+ * contributions from numerous individuals and organizations.
+ * Please see the COPYING and CONTRIBUTORS files for details.
+ */
+
+#include "squid.h"
+#include "comm/Connection.h"
+#include "errorpage.h"
+#include "security/EncryptorAnswer.h"
+
+Security::EncryptorAnswer::~EncryptorAnswer()
+{
+ delete error.get();
+}
+
+std::ostream &
+Security::operator <<(std::ostream &os, const Security::EncryptorAnswer &answer)
+{
+ return os << answer.conn << ", " << answer.error;
+}
+
--- /dev/null
+/*
+ * Copyright (C) 1996-2015 The Squid Software Foundation and contributors
+ *
+ * Squid software is distributed under GPLv2+ license and includes
+ * contributions from numerous individuals and organizations.
+ * Please see the COPYING and CONTRIBUTORS files for details.
+ */
+
+#ifndef SQUID_SECURITY_ENCRYPTORANSWER_H
+#define SQUID_SECURITY_ENCRYPTORANSWER_H
+
+#include "base/CbcPointer.h"
+#include "comm/forward.h"
+
+class ErrorState;
+
+namespace Security {
+
+/// Peer encrypted connection setup results (supplied via a callback).
+/// The connection to peer was secured if and only if the error member is nil.
+class EncryptorAnswer
+{
+public:
+ ~EncryptorAnswer(); ///< deletes error if it is still set
+ Comm::ConnectionPointer conn; ///< peer connection (secured on success)
+
+ /// answer recepients must clear the error member in order to keep its info
+ /// XXX: We should refcount ErrorState instead of cbdata-protecting it.
+ CbcPointer<ErrorState> error; ///< problem details (nil on success)
+};
+
+std::ostream &operator <<(std::ostream &, const Security::EncryptorAnswer &);
+
+} // namepace Security
+
+#endif /* SQUID_SECURITY_ENCRYPTORANSWER_H */
+
libsecurity_la_SOURCES= \
Context.h \
+ EncryptorAnswer.cc \
+ EncryptorAnswer.h \
+ forward.h \
PeerOptions.cc \
PeerOptions.h
#include "ConfigParser.h"
#include "SBuf.h"
-#include "security/Context.h"
+#include "security/forward.h"
namespace Security
{
class PeerOptions
{
public:
- PeerOptions() : sslVersion(0), encryptTransport(false) {}
+ PeerOptions() : parsedOptions(0), sslVersion(0), encryptTransport(false) {}
/// parse a TLS squid.conf option
void parse(const char *);
--- /dev/null
+/*
+ * Copyright (C) 1996-2015 The Squid Software Foundation and contributors
+ *
+ * Squid software is distributed under GPLv2+ license and includes
+ * contributions from numerous individuals and organizations.
+ * Please see the COPYING and CONTRIBUTORS files for details.
+ */
+
+#ifndef SQUID_SRC_SECURITY_FORWARD_H
+#define SQUID_SRC_SECURITY_FORWARD_H
+
+#include "security/Context.h"
+
+/// Network/connection security abstraction layer
+namespace Security
+{
+
+class EncryptorAnswer;
+class PeerOptions;
+
+} // namespace Security
+
+#endif /* SQUID_SRC_SECURITY_FORWARD_H */
+
callback(aCallback),
negotiationTimeout(timeout),
startTime(squid_curtime),
- splice(false)
+ splice(false),
+ resumingSession(false),
+ serverCertificateHandled(false)
{
// if this throws, the caller's cb dialer is not our CbDialer
Must(dynamic_cast<CbDialer*>(callback->getDialer()));
assert(!peer->secure.sslDomain.isEmpty());
// const loss is okay here, ssl_ex_index_server is only read and not assigned a destructor
- const char *host = const_cast<SBuf*>(&peer->secure.sslDomain)->c_str();
- SSL_set_ex_data(ssl, ssl_ex_index_server, const_cast<char*>(host));
+ SBuf *host = new SBuf(peer->secure.sslDomain);
+ SSL_set_ex_data(ssl, ssl_ex_index_server, host);
if (peer->sslSession)
SSL_set_session(ssl, peer->sslSession);
// client connection is required in the case we need to splice
// or terminate client and server connections
assert(clientConn != NULL);
- const char *hostName = NULL;
+ SBuf *hostName = NULL;
Ssl::ClientBio *cltBio = NULL;
+ //Enable Status_request tls extension, required to bump some clients
+ SSL_set_tlsext_status_type(ssl, TLSEXT_STATUSTYPE_ocsp);
+
// In server-first bumping mode, clientSsl is NULL.
if (SSL *clientSsl = fd_table[clientConn->fd].ssl) {
BIO *b = SSL_get_rbio(clientSsl);
cltBio = static_cast<Ssl::ClientBio *>(b->ptr);
const Ssl::Bio::sslFeatures &features = cltBio->getFeatures();
if (!features.serverName.isEmpty())
- hostName = features.serverName.c_str();
+ hostName = new SBuf(features.serverName);
}
if (!hostName) {
// unless it was the CONNECT request with a user-typed address.
const bool isConnectRequest = !csd->port->flags.isIntercepted();
if (!request->flags.sslPeek || isConnectRequest)
- hostName = request->GetHost();
+ hostName = new SBuf(request->GetHost());
}
if (hostName)
assert(cltBio);
const Ssl::Bio::sslFeatures &features = cltBio->getFeatures();
if (features.sslVersion != -1) {
- features.applyToSSL(ssl);
+ features.applyToSSL(ssl, csd->sslBumpMode);
// Should we allow it for all protocols?
if (features.sslVersion >= 3) {
BIO *b = SSL_get_rbio(ssl);
// Use SNI TLS extension only when we connect directly
// to the origin server and we know the server host name.
- const char *sniServer = hostName ? hostName :
+ const char *sniServer = hostName ? hostName->c_str() :
(!request->GetHostIsNumeric() ? request->GetHost() : NULL);
if (sniServer)
Ssl::setClientSNI(ssl, sniServer);
callBack();
}
+void
+Ssl::PeerConnector::handleServerCertificate()
+{
+ if (serverCertificateHandled)
+ return;
+
+ if (ConnStateData *csd = request->clientConnectionManager.valid()) {
+ const int fd = serverConnection()->fd;
+ SSL *ssl = fd_table[fd].ssl;
+ Ssl::X509_Pointer serverCert(SSL_get_peer_certificate(ssl));
+ if (!serverCert.get())
+ return;
+
+ serverCertificateHandled = true;
+
+ csd->resetSslCommonName(Ssl::CommonHostName(serverCert.get()));
+ debugs(83, 5, "HTTPS server CN: " << csd->sslCommonName() <<
+ " bumped: " << *serverConnection());
+
+ // remember the server certificate for later use
+ if (Ssl::ServerBump *serverBump = csd->serverBump()) {
+ serverBump->serverCert.reset(serverCert.release());
+ }
+ }
+}
+
bool
Ssl::PeerConnector::sslFinalized()
{
const int fd = serverConnection()->fd;
SSL *ssl = fd_table[fd].ssl;
- if (request->clientConnectionManager.valid()) {
- // remember the server certificate from the ErrorDetail object
- if (Ssl::ServerBump *serverBump = request->clientConnectionManager->serverBump()) {
- serverBump->serverCert.reset(SSL_get_peer_certificate(ssl));
+ // In the case the session is resuming, the certificates does not exist and
+ // we did not do any cert validation
+ if (resumingSession)
+ return true;
+ handleServerCertificate();
+
+ if (ConnStateData *csd = request->clientConnectionManager.valid()) {
+ if (Ssl::ServerBump *serverBump = csd->serverBump()) {
// remember validation errors, if any
if (Ssl::CertErrors *errs = static_cast<Ssl::CertErrors *>(SSL_get_ex_data(ssl, ssl_ex_index_ssl_errors)))
serverBump->sslErrors = cbdataReference(errs);
void
Ssl::PeerConnector::checkForPeekAndSplice()
{
- SSL *ssl = fd_table[serverConn->fd].ssl;
// Mark Step3 of bumping
if (request->clientConnectionManager.valid()) {
if (Ssl::ServerBump *serverBump = request->clientConnectionManager->serverBump()) {
serverBump->step = Ssl::bumpStep3;
- if (!serverBump->serverCert.get())
- serverBump->serverCert.reset(SSL_get_peer_certificate(ssl));
}
}
+ handleServerCertificate();
+
ACLFilledChecklist *acl_checklist = new ACLFilledChecklist(
::Config.accessList.ssl_bump,
request.getRaw(), NULL);
return;
case SSL_ERROR_WANT_WRITE:
- if ((request->clientConnectionManager->sslBumpMode == Ssl::bumpPeek || request->clientConnectionManager->sslBumpMode == Ssl::bumpStare) && srvBio->holdWrite()) {
+ if ((srvBio->bumpMode() == Ssl::bumpPeek || srvBio->bumpMode() == Ssl::bumpStare) && srvBio->holdWrite()) {
debugs(81, DBG_IMPORTANT, "hold write on SSL connection on FD " << fd);
checkForPeekAndSplice();
return;
case SSL_ERROR_SYSCALL:
ssl_lib_error = ERR_get_error();
+ // In Peek mode, the ClientHello message sent to the server. If the
+ // server resuming a previous (spliced) SSL session with the client,
+ // then probably we are here because local SSL object does not know
+ // anything about the session being resumed.
+ //
+ if (srvBio->bumpMode() == Ssl::bumpPeek && (resumingSession = srvBio->resumingSession())) {
+ // we currently splice all resumed sessions unconditionally
+ if (const bool spliceResumed = true) {
+ checkForPeekAndSpliceDone(Ssl::bumpSplice);
+ return;
+ } // else fall through to find a matching ssl_bump action (with limited info)
+ }
+
// If we are in peek-and-splice mode and still we did not write to
// server yet, try to see if we should splice.
// In this case the connection can be saved.
// unsupported server Hello message (TODO: make configurable).
#if 1
if (!SSL_get_ex_data(ssl, ssl_ex_index_ssl_error_detail) &&
- SSL_get_peer_certificate(ssl) &&
- (request->clientConnectionManager->sslBumpMode == Ssl::bumpPeek || request->clientConnectionManager->sslBumpMode == Ssl::bumpStare) && srvBio->holdWrite()) {
- debugs(81, 3, "Error (" << ERR_error_string(ssl_lib_error, NULL) << ") but, hold write on SSL connection on FD " << fd);
- checkForPeekAndSplice();
- return;
+ (srvBio->bumpMode() == Ssl::bumpPeek || srvBio->bumpMode() == Ssl::bumpStare) && srvBio->holdWrite()) {
+ Ssl::X509_Pointer serverCert(SSL_get_peer_certificate(ssl));
+ if (serverCert.get()) {
+ debugs(81, 3, "Error (" << ERR_error_string(ssl_lib_error, NULL) << ") but, hold write on SSL connection on FD " << fd);
+ checkForPeekAndSplice();
+ return;
+ }
}
#endif
return buf.content();
}
-/* PeerConnectorAnswer */
-
-Ssl::PeerConnectorAnswer::~PeerConnectorAnswer()
-{
- delete error.get();
-}
-
-std::ostream &
-Ssl::operator <<(std::ostream &os, const Ssl::PeerConnectorAnswer &answer)
-{
- return os << answer.conn << ", " << answer.error;
-}
-
#include "acl/Acl.h"
#include "base/AsyncCbdataCalls.h"
#include "base/AsyncJob.h"
+#include "security/EncryptorAnswer.h"
#include "ssl/support.h"
#include <iosfwd>
class ErrorDetail;
class CertValidationResponse;
-/// PeerConnector results (supplied via a callback).
-/// The connection to peer was secured if and only if the error member is nil.
-class PeerConnectorAnswer
-{
-public:
- ~PeerConnectorAnswer(); ///< deletes error if it is still set
- Comm::ConnectionPointer conn; ///< peer connection (secured on success)
-
- /// answer recepients must clear the error member in order to keep its info
- /// XXX: We should refcount ErrorState instead of cbdata-protecting it.
- CbcPointer<ErrorState> error; ///< problem details (nil on success)
-};
-
/**
\par
* Connects Squid client-side to an SSL peer (cache_peer ... ssl).
* Used by TunnelStateData, FwdState, and PeerPoolMgr to start talking to an
* SSL peer.
\par
- * The caller receives a call back with PeerConnectorAnswer. If answer.error
+ * The caller receives a call back with Security::EncryptorAnswer. If answer.error
* is not nil, then there was an error and the SSL connection to the SSL peer
* was not fully established. The error object is suitable for error response
* generation.
public:
virtual ~CbDialer() {}
/// gives PeerConnector access to the in-dialer answer
- virtual PeerConnectorAnswer &answer() = 0;
+ virtual Security::EncryptorAnswer &answer() = 0;
};
typedef RefCount<HttpRequest> HttpRequestPointer;
/// Check SSL errors returned from cert validator against sslproxy_cert_error access list
Ssl::CertErrors *sslCrtvdCheckForErrors(Ssl::CertValidationResponse const &, Ssl::ErrorDetail *&);
+ /// Updates associated client connection manager members
+ /// if the server certificate was received from the server.
+ void handleServerCertificate();
+
/// Callback function called when squid receive message from cert validator helper
static void sslCrtvdHandleReplyWrapper(void *data, Ssl::CertValidationResponse const &);
time_t negotiationTimeout; ///< the ssl connection timeout to use
time_t startTime; ///< when the peer connector negotiation started
bool splice; ///< Whether we are going to splice or not
+ bool resumingSession; ///< whether it is an SSL resuming session connection
+ bool serverCertificateHandled; ///< whether handleServerCertificate() succeeded
};
-std::ostream &operator <<(std::ostream &os, const Ssl::PeerConnectorAnswer &a);
-
} // namespace Ssl
#endif /* SQUID_PEER_CONNECTOR_H */
bool
Ssl::ClientBio::isClientHello(int state)
{
- return (state == SSL2_ST_GET_CLIENT_HELLO_A ||
- state == SSL3_ST_SR_CLNT_HELLO_A ||
- state == SSL23_ST_SR_CLNT_HELLO_A ||
- state == SSL23_ST_SR_CLNT_HELLO_B ||
- state == SSL3_ST_SR_CLNT_HELLO_B ||
- state == SSL3_ST_SR_CLNT_HELLO_C
+ return (
+ state == SSL3_ST_SR_CLNT_HELLO_A ||
+ state == SSL23_ST_SR_CLNT_HELLO_A ||
+ state == SSL23_ST_SR_CLNT_HELLO_B ||
+ state == SSL3_ST_SR_CLNT_HELLO_B ||
+ state == SSL3_ST_SR_CLNT_HELLO_C
);
}
}
if (helloState == atHelloNone) {
-
- const unsigned char *head = (const unsigned char *)rbuf.content();
- const char *s = objToString(head, rbuf.contentSize());
- debugs(83, 7, "SSL Header: " << s);
- if (rbuf.contentSize() < 5) {
+ helloSize = features.parseMsgHead(rbuf);
+ if (helloSize == 0) {
+ // Not enough bytes to get hello message size
BIO_set_retry_read(table);
- return 0;
- }
-
- if (head[0] == 0x16) {
- debugs(83, 7, "SSL version 3 handshake message");
- helloSize = (head[3] << 8) + head[4];
- debugs(83, 7, "SSL Header Size: " << helloSize);
- helloSize +=5;
-#if defined(DO_SSLV23)
- } else if ((head[0] & 0x80) && head[2] == 0x01 && head[3] == 0x03) {
- debugs(83, 7, "SSL version 2 handshake message with v3 support");
- helloSize = head[1];
- helloSize +=5;
-#endif
- } else {
- debugs(83, 7, "Not an SSL acceptable handshake message (SSLv2 message?)");
+ return -1;
+ } else if (helloSize < 0) {
wrongProtocol = true;
return -1;
}
BIO_set_retry_read(table);
return -1;
}
- features.get((const unsigned char *)rbuf.content());
+ features.get(rbuf);
helloState = atHelloReceived;
}
void
Ssl::ServerBio::setClientFeatures(const Ssl::Bio::sslFeatures &features)
{
- clientFeatures.sslVersion = features.sslVersion;
- clientFeatures.compressMethod = features.compressMethod;
- clientFeatures.serverName = features.serverName;
- clientFeatures.clientRequestedCiphers = features.clientRequestedCiphers;
- clientFeatures.unknownCiphers = features.unknownCiphers;
- memcpy(clientFeatures.client_random, features.client_random, SSL3_RANDOM_SIZE);
- clientFeatures.helloMessage.clear();
- clientFeatures.helloMessage.append(features.helloMessage.rawContent(), features.helloMessage.length());
- clientFeatures.doHeartBeats = features.doHeartBeats;
- clientFeatures.extensions = features.extensions;
- featuresSet = true;
+ clientFeatures = features;
};
int
// If the client supports compression but our context does not support
// we can not adjust.
- if (features.compressMethod && ssl->ctx->comp_methods == NULL) {
+#if !defined(OPENSSL_NO_COMP)
+ const bool requireCompression = (features.compressMethod && ssl->ctx->comp_methods == NULL);
+#else
+ const bool requireCompression = features.compressMethod;
+#endif
+ if (requireCompression) {
debugs(83, 5, "Client Hello Data supports compression, but we do not!");
return false;
}
assert(helloMsg.isEmpty());
SSL *ssl = fd_table[fd_].ssl;
- if (featuresSet && ssl) {
+ if (clientFeatures.initialized_ && ssl) {
if (bumpMode_ == Ssl::bumpPeek) {
if (adjustSSL(ssl, clientFeatures))
allowBump = true;
}
}
+bool
+Ssl::ServerBio::resumingSession()
+{
+ if (!serverFeatures.initialized_)
+ serverFeatures.get(rbuf, false);
+
+ if (!clientFeatures.sessionId.isEmpty() && !serverFeatures.sessionId.isEmpty())
+ return clientFeatures.sessionId == serverFeatures.sessionId;
+
+ // is this a session resuming attempt using TLS tickets?
+ if (clientFeatures.hasTlsTicket &&
+ serverFeatures.tlsTicketsExtension &&
+ serverFeatures.hasCcsOrNst)
+ return true;
+
+ return false;
+}
+
/// initializes BIO table after allocation
static int
squid_bio_create(BIO *bi)
}
}
-Ssl::Bio::sslFeatures::sslFeatures(): sslVersion(-1), compressMethod(-1), unknownCiphers(false), doHeartBeats(true)
+Ssl::Bio::sslFeatures::sslFeatures(): sslVersion(-1), compressMethod(-1), helloMsgSize(0), unknownCiphers(false), doHeartBeats(true), tlsTicketsExtension(false), hasTlsTicket(false), tlsStatusRequest(false), hasCcsOrNst(false), initialized_(false)
{
memset(client_random, 0, SSL3_RANDOM_SIZE);
}
debugs(83, 7, "SNI server name: " << serverName);
#endif
+#if !defined(OPENSSL_NO_COMP)
if (ssl->session->compress_meth)
compressMethod = ssl->session->compress_meth;
else if (sslVersion >= 3) //if it is 3 or newer version then compression is disabled
+#endif
compressMethod = 0;
debugs(83, 7, "SSL compression: " << compressMethod);
opaquePrf = objToString(p, len);
}
#endif
+ initialized_ = true;
return true;
}
+int
+Ssl::Bio::sslFeatures::parseMsgHead(const MemBuf &buf)
+{
+ const unsigned char *head = (const unsigned char *)buf.content();
+ const char *s = objToString(head, buf.contentSize());
+ debugs(83, 7, "SSL Header: " << s);
+ if (buf.contentSize() < 5)
+ return 0;
+
+ if (helloMsgSize > 0)
+ return helloMsgSize;
+
+ // Check for SSLPlaintext/TLSPlaintext record
+ // RFC6101 section 5.2.1
+ // RFC5246 section 6.2.1
+ if (head[0] == 0x16) {
+ debugs(83, 7, "SSL version 3 handshake message");
+ // The SSL version exist in the 2nd and 3rd bytes
+ sslVersion = (head[1] << 8) | head[2];
+ debugs(83, 7, "SSL Version :" << std::hex << std::setw(8) << std::setfill('0') << sslVersion);
+ // The hello message size exist in 4th and 5th bytes
+ helloMsgSize = (head[3] << 8) + head[4];
+ debugs(83, 7, "SSL Header Size: " << helloMsgSize);
+ helloMsgSize +=5;
+#if defined(DO_SSLV23)
+ } else if ((head[0] & 0x80) && head[2] == 0x01 && head[3] == 0x03) {
+ debugs(83, 7, "SSL version 2 handshake message with v3 support");
+ sslVersion = (hello[3] << 8) | hello[4];
+ debugs(83, 7, "SSL Version :" << std::hex << std::setw(8) << std::setfill('0') << sslVersion);
+ // The hello message size exist in 2nd byte
+ helloMsgSize = head[1];
+ helloMsgSize +=2;
+#endif
+ } else {
+ debugs(83, 7, "Not an SSL acceptable handshake message (SSLv2 message?)");
+ return (helloMsgSize = -1);
+ }
+
+ // Set object as initialized. Even if we did not full parsing yet
+ // The basic features, like the SSL version is set
+ initialized_ = true;
+ return helloMsgSize;
+}
+
bool
-Ssl::Bio::sslFeatures::get(const unsigned char *hello)
+Ssl::Bio::sslFeatures::checkForCcsOrNst(const unsigned char *msg, size_t size)
{
- // The SSL handshake message should starts with a 0x16 byte
- if (hello[0] == 0x16) {
- return parseV3Hello(hello);
+ while (size > 5) {
+ const int msgType = msg[0];
+ const int msgSslVersion = (msg[1] << 8) | msg[2];
+ debugs(83, 7, "SSL Message Version :" << std::hex << std::setw(8) << std::setfill('0') << msgSslVersion);
+ // Check for Change Cipher Spec message
+ // RFC5246 section 6.2.1
+ if (msgType == 0x14) {// Change Cipher Spec message found
+ debugs(83, 7, "SSL Change Cipher Spec message found");
+ return true;
+ }
+ // Check for New Session Ticket message
+ // RFC5077 section 3.3
+ if (msgType == 0x04) {// New Session Ticket message found
+ debugs(83, 7, "TLS New Session Ticket message found");
+ return true;
+ }
+ // The hello message size exist in 4th and 5th bytes
+ size_t msgLength = (msg[3] << 8) + msg[4];
+ debugs(83, 7, "SSL Message Size: " << msgLength);
+ msgLength += 5;
+
+ if (msgLength <= size) {
+ msg += msgLength;
+ size -= msgLength;
+ } else
+ size = 0;
+ }
+ return false;
+}
+
+bool
+Ssl::Bio::sslFeatures::get(const MemBuf &buf, bool record)
+{
+ int msgSize;
+ if ((msgSize = parseMsgHead(buf)) <= 0) {
+ debugs(83, 7, "Not a known SSL handshake message");
+ return false;
+ }
+
+ if (msgSize > buf.contentSize()) {
+ debugs(83, 2, "Partial SSL handshake message, can not parse!");
+ return false;
+ }
+
+ if (record) {
+ helloMessage.clear();
+ helloMessage.append(buf.content(), buf.contentSize());
+ }
+
+ const unsigned char *msg = (const unsigned char *)buf.content();
#if defined(DO_SSLV23)
- } else if ((hello[0] & 0x80) && hello[2] == 0x01 && hello[3] == 0x03) {
- return parseV23Hello(hello);
+ if (msg[0] & 0x80)
+ return parseV23Hello(msg, (size_t)msgSize);
+ else
#endif
+ {
+ // Hello messages require 5 bytes header + 1 byte Msg type + 3 bytes for Msg size
+ if (buf.contentSize() < 9)
+ return false;
+
+ // Check for the Handshake/Message type
+ // The type 2 is a ServerHello, the type 1 is a ClientHello
+ // RFC5246 section 7.4
+ if (msg[5] == 0x2) { // ServerHello message
+ if (parseV3ServerHello(msg, (size_t)msgSize)) {
+ hasCcsOrNst = checkForCcsOrNst(msg + msgSize, buf.contentSize() - msgSize);
+ return true;
+ }
+ } else if (msg[5] == 0x1) // ClientHello message,
+ return parseV3Hello(msg, (size_t)msgSize);
}
- debugs(83, 7, "Not a known SSL handshake message");
return false;
}
bool
-Ssl::Bio::sslFeatures::parseV3Hello(const unsigned char *hello)
+Ssl::Bio::sslFeatures::parseV3ServerHello(const unsigned char *hello, size_t size)
{
- debugs(83, 7, "Get fake features from v3 hello message.");
- // The SSL version exist in the 2nd and 3rd bytes
- sslVersion = (hello[1] << 8) | hello[2];
- debugs(83, 7, "Get fake features. Version :" << std::hex << std::setw(8) << std::setfill('0')<< sslVersion);
+ // Parse a ServerHello Handshake message
+ // RFC5246 section 7.4, 7.4.1.3
+ // The ServerHello starts at hello+5
+ const size_t helloSize = (hello[6] << 16) | (hello[7] << 8) | hello[8];
+ debugs(83, 7, "ServerHello message size: " << helloSize);
+ // helloSize should be msgSize + hello Header (4 bytes)
+ if (helloSize + 4 > size) {
+ debugs(83, 2, "ServerHello parse error");
+ return false;
+ }
+
+ // helloSize should be at least 38 bytes long:
+ // (SSL Version + Random + SessionId Length + Cipher Suite + Compression Method)
+ if (helloSize < 38) {
+ debugs(83, 2, "Too short ServerHello message");
+ return false;
+ }
+
+ debugs(83, 7, "Get fake features from v3 ServerHello message.");
+ // Get the correct version of the sub-hello message
+ sslVersion = (hello[9] << 8) | hello[10];
+ // At the position 43 (MsgHeader(5 bytes) + HelloHeader (6bytes) + SSL3_RANDOM_SIZE (32bytes))
+ const size_t sessIdLen = (size_t)hello[43];
+ debugs(83, 7, "Session ID Length: " << sessIdLen);
+
+ // The size should be enough to hold at least the following
+ // 5 MsgHelloHeader + 4 (hello header)
+ // + 2 (SSL Version) + 32 (random) + 1 (sessionId length)
+ // + sessIdLength + 2 (cipher suite) + 1 (compression method)
+ // = 47 + sessIdLength
+ if (47 + sessIdLen > size) {
+ debugs(83, 2, "ciphers length parse error");
+ return false;
+ }
+
+ // The sessionID stored at 44 position, after sessionID length field
+ sessionId.assign((const char *)(hello + 44), sessIdLen);
+
+ // Check if there are extensions in hello message
+ // RFC5246 section 7.4.1.4
+ if (size > 47 + sessIdLen + 2) {
+ // 47 + sessIdLen
+ const unsigned char *pToExtensions = hello + 47 + sessIdLen;
+ const size_t extensionsLen = (pToExtensions[0] << 8) | pToExtensions[1];
+ // Check if the hello size can hold extensions
+ if (47 + 2 + sessIdLen + extensionsLen > size ) {
+ debugs(83, 2, "Extensions length parse error");
+ return false;
+ }
+
+ pToExtensions += 2;
+ const unsigned char *ext = pToExtensions;
+ while (ext + 4 <= pToExtensions + extensionsLen) {
+ const short extType = (ext[0] << 8) | ext[1];
+ ext += 2;
+ const short extLen = (ext[0] << 8) | ext[1];
+ ext += 2;
+ debugs(83, 7, "TLS Extension: " << std::hex << extType << " of size:" << extLen);
+ // SessionTicket TLS Extension, RFC5077 section 3.2
+ if (extType == 0x23) {
+ tlsTicketsExtension = true;
+ }
+ ext += extLen;
+ }
+ }
+ return true;
+}
+
+bool
+Ssl::Bio::sslFeatures::parseV3Hello(const unsigned char *hello, size_t size)
+{
+ // Parse a ClientHello Handshake message
+ // RFC5246 section 7.4, 7.4.1.2
+ // The ClientHello starts at hello+5
+
+ debugs(83, 7, "Get fake features from v3 ClientHello message.");
+ const size_t helloSize = (hello[6] << 16) | (hello[7] << 8) | hello[8];
+ debugs(83, 7, "ClientHello message size: " << helloSize);
+ // helloSize should be size + hello Header (4 bytes)
+ if (helloSize + 4 > size) {
+ debugs(83, 2, "ClientHello parse error");
+ return false;
+ }
- // The following hello message size exist in 4th and 5th bytes
- int helloSize = (hello[3] << 8) | hello[4];
- helloSize += 5; //Include the 5 header bytes.
- helloMessage.clear();
- helloMessage.append((const char *)hello, helloSize);
+ // helloSize should be at least 38 bytes long:
+ // (SSL Version(2) + Random(32) + SessionId Length(1) + Cipher Suite Length(2) + Compression Method Length(1))
+ if (helloSize < 38) {
+ debugs(83, 2, "Too short ClientHello message");
+ return false;
+ }
//For SSLv3 or TLSv1.* protocols we can get some more informations
if (hello[1] == 0x3 && hello[5] == 0x1 /*HELLO A message*/) {
debugs(83, 7, "Client random: " << objToString(client_random, SSL3_RANDOM_SIZE));
// At the position 43 (11+SSL3_RANDOM_SIZE)
- int sessIDLen = (int)hello[43];
+ const size_t sessIDLen = (size_t)hello[43];
debugs(83, 7, "Session ID Length: " << sessIDLen);
+ // The size should be enough to hold at least the following
+ // 5 MsgHelloHeader + 4 (hello header)
+ // + 2 (SSL Version) + 32 (random) + 1 (sessionId length)
+ // + sessIdLength + 2 (cipher suite length) + 1 (compression method length)
+ // = 47 + sessIdLength
+ if (47 + sessIDLen > size)
+ return false;
+
+ // The sessionID stored art 44 position, after sessionID length field
+ sessionId.assign((const char *)(hello + 44), sessIDLen);
+
//Ciphers list. It is stored after the Session ID.
+ // It is a variable-length vector(RFC5246 section 4.3)
const unsigned char *ciphers = hello + 44 + sessIDLen;
- int ciphersLen = (ciphers[0] << 8) | ciphers[1];
+ const size_t ciphersLen = (ciphers[0] << 8) | ciphers[1];
+ if (47 + sessIDLen + ciphersLen > size) {
+ debugs(83, 2, "ciphers length parse error");
+ return false;
+ }
+
ciphers += 2;
if (ciphersLen) {
const SSL_METHOD *method = SSLv3_method();
- int cs = method->put_cipher_by_char(NULL, NULL);
+ const int cs = method->put_cipher_by_char(NULL, NULL);
assert(cs > 0);
- for (int i = 0; i < ciphersLen; i += cs) {
+ for (size_t i = 0; i < ciphersLen; i += cs) {
const SSL_CIPHER *c = method->get_cipher_by_char((ciphers + i));
if (c != NULL) {
if (!clientRequestedCiphers.empty())
compressMethod = 0;
debugs(83, 7, "SSL compression methods number: " << (int)compression[0]);
+ // Parse Extensions, RFC5246 section 7.4.1.4
const unsigned char *pToExtensions = compression + 1 + (int)compression[0];
- if (pToExtensions < hello + helloSize) {
- int extensionsLen = (pToExtensions[0] << 8) | pToExtensions[1];
- const unsigned char *ext = pToExtensions + 2;
- while (ext < pToExtensions + extensionsLen) {
- short extType = (ext[0] << 8) | ext[1];
+ if ((size_t)((pToExtensions - hello) + 2) < size) {
+ const size_t extensionsLen = (pToExtensions[0] << 8) | pToExtensions[1];
+ if ((pToExtensions - hello) + 2 + extensionsLen > size) {
+ debugs(83, 2, "Extensions length parse error");
+ return false;
+ }
+
+ pToExtensions += 2;
+ const unsigned char *ext = pToExtensions;
+ while (ext + 4 <= pToExtensions + extensionsLen) {
+ const short extType = (ext[0] << 8) | ext[1];
ext += 2;
- short extLen = (ext[0] << 8) | ext[1];
+ const short extLen = (ext[0] << 8) | ext[1];
ext += 2;
- debugs(83, 7, "SSL Exntension: " << std::hex << extType << " of size:" << extLen);
+ debugs(83, 7, "TLS Extension: " << std::hex << extType << " of size:" << extLen);
+
+ if (ext + extLen > pToExtensions + extensionsLen) {
+ debugs(83, 2, "Extension " << std::hex << extType << " length parser error");
+ return false;
+ }
+
//The SNI extension has the type 0 (extType == 0)
+ // RFC6066 sections 3, 10.2
// The two first bytes indicates the length of the SNI data (should be extLen-2)
// The next byte is the hostname type, it should be '0' for normal hostname (ext[2] == 0)
// The 3rd and 4th bytes are the length of the hostname
if (extType == 0 && ext[2] == 0) {
- int hostLen = (ext[3] << 8) | ext[4];
+ const int hostLen = (ext[3] << 8) | ext[4];
serverName.assign((const char *)(ext+5), hostLen);
debugs(83, 7, "Found server name: " << serverName);
} else if (extType == 15 && ext[0] != 0) {
- // The heartBeats are the type 15
+ // The heartBeats are the type 15, RFC6520
doHeartBeats = true;
+ } else if (extType == 0x23) {
+ //SessionTicket TLS Extension RFC5077
+ tlsTicketsExtension = true;
+ if (extLen != 0)
+ hasTlsTicket = true;
+ } else if (extType == 0x05) {
+ // RFC6066 sections 8, 10.2
+ tlsStatusRequest = true;
+ } else if (extType == 0x3374) {
+ // detected TLS next protocol negotiate extension
+ } else if (extType == 0x10) {
+ // Application-Layer Protocol Negotiation Extension, RFC7301
+ const int listLen = (ext[0] << 8) | ext[1];
+ if (listLen < extLen)
+ tlsAppLayerProtoNeg.assign((const char *)(ext+5), listLen);
} else
extensions.push_back(extType);
}
bool
-Ssl::Bio::sslFeatures::parseV23Hello(const unsigned char *hello)
+Ssl::Bio::sslFeatures::parseV23Hello(const unsigned char *hello, size_t size)
{
#if defined(DO_SSLV23)
- debugs(83, 7, "Get fake features from v23 hello message.");
- sslVersion = (hello[3] << 8) | hello[4];
- debugs(83, 7, "Get fake features. Version :" << std::hex << std::setw(8) << std::setfill('0')<< sslVersion);
-
- // The following hello message size exist in 2nd byte
- int helloSize = hello[1];
- helloSize += 2; //Include the 2 header bytes.
- helloMessage.clear();
- helloMessage.append((char *)hello, helloSize);
-
+ debugs(83, 7, "Get fake features from v23 ClientHello message.");
+ if (size < 7)
+ return false;
//Ciphers list. It is stored after the Session ID.
-
- int ciphersLen = (hello[5] << 8) | hello[6];
+ const int ciphersLen = (hello[5] << 8) | hello[6];
const unsigned char *ciphers = hello + 11;
+
+ if (size < ciphersLen + 11 + SSL3_RANDOM_SIZE)
+ return false;
+
if (ciphersLen) {
const SSL_METHOD *method = SSLv23_method();
int cs = method->put_cipher_by_char(NULL, NULL);
}
void
-Ssl::Bio::sslFeatures::applyToSSL(SSL *ssl) const
+Ssl::Bio::sslFeatures::applyToSSL(SSL *ssl, Ssl::BumpMode bumpMode) const
{
// To increase the possibility for bumping after peek mode selection or
// splicing after stare mode selection it is good to set the
SSL_set_options(ssl, SSL_OP_NO_COMPRESSION);
#endif
+#if defined(TLSEXT_STATUSTYPE_ocsp)
+ if (tlsStatusRequest)
+ SSL_set_tlsext_status_type(ssl, TLSEXT_STATUSTYPE_ocsp);
+#endif
+
+#if defined(TLSEXT_TYPE_application_layer_protocol_negotiation)
+ if (!tlsAppLayerProtoNeg.isEmpty()) {
+ if (bumpMode == Ssl::bumpPeek)
+ SSL_set_alpn_protos(ssl, (const unsigned char*)tlsAppLayerProtoNeg.rawContent(), tlsAppLayerProtoNeg.length());
+ else {
+ static const unsigned char supported_protos[] = {8, 'h','t','t', 'p', '/', '1', '.', '1'};
+ SSL_set_alpn_protos(ssl, supported_protos, sizeof(supported_protos));
+ }
+ }
+#endif
}
std::ostream &
Ssl::Bio::sslFeatures::print(std::ostream &os) const
{
static std::string buf;
+ // TODO: Also print missing features like the HeartBeats and AppLayerProtoNeg
return os << "v" << sslVersion <<
" SNI:" << (serverName.isEmpty() ? SBuf("-") : serverName) <<
" comp:" << compressMethod <<
public:
sslFeatures();
bool get(const SSL *ssl); ///< Retrieves the features from SSL object
- bool get(const unsigned char *hello); ///< Retrieves the features from raw SSL hello message
- bool parseV3Hello(const unsigned char *hello);
- bool parseV23Hello(const unsigned char *hello);
+ /// Retrieves features from raw SSL Hello message.
+ /// \param record whether to store Message to the helloMessage member
+ bool get(const MemBuf &, bool record = true);
+ /// Parses a v3 ClientHello message
+ bool parseV3Hello(const unsigned char *hello, size_t helloSize);
+ /// Parses a v23 ClientHello message
+ bool parseV23Hello(const unsigned char *hello, size_t helloSize);
+ /// Parses a v3 ServerHello message.
+ bool parseV3ServerHello(const unsigned char *hello, size_t helloSize);
/// Prints to os stream a human readable form of sslFeatures object
std::ostream & print(std::ostream &os) const;
/// Converts to the internal squid SSL version form the sslVersion
int toSquidSSLVersion() const;
/// Configure the SSL object with the SSL features of the sslFeatures object
- void applyToSSL(SSL *ssl) const;
+ void applyToSSL(SSL *ssl, Ssl::BumpMode bumpMode) const;
+ /// Parses an SSL Message header. It returns the ssl Message size.
+ /// \retval >0 if the hello size is retrieved
+ /// \retval 0 if the contents of the buffer are not enough
+ /// \retval <0 if the contents of buf are not SSLv3 or TLS hello message
+ int parseMsgHead(const MemBuf &);
+ /// Parses msg buffer and return true if one of the Change Cipher Spec
+ /// or New Session Ticket messages found
+ bool checkForCcsOrNst(const unsigned char *msg, size_t size);
public:
int sslVersion; ///< The requested/used SSL version
int compressMethod; ///< The requested/used compressed method
+ int helloMsgSize; ///< the hello message size
mutable SBuf serverName; ///< The SNI hostname, if any
std::string clientRequestedCiphers; ///< The client requested ciphers
bool unknownCiphers; ///< True if one or more ciphers are unknown
std::string ellipticCurves; ///< tlsExtension ellipticCurveList
std::string opaquePrf; ///< tlsExtension opaquePrf
bool doHeartBeats;
+ bool tlsTicketsExtension; ///< whether TLS tickets extension is enabled
+ bool hasTlsTicket; ///< whether a TLS ticket is included
+ bool tlsStatusRequest; ///< whether the TLS status request extension is set
+ SBuf tlsAppLayerProtoNeg; ///< The value of the TLS application layer protocol extension if it is enabled
+ /// whether Change Cipher Spec message included in ServerHello
+ /// handshake message
+ bool hasCcsOrNst;
/// The client random number
unsigned char client_random[SSL3_RANDOM_SIZE];
+ SBuf sessionId;
std::list<int> extensions;
SBuf helloMessage;
+ bool initialized_;
};
explicit Bio(const int anFd);
virtual ~Bio();
/// to socket and sets the "read retry" flag of the BIO to true
virtual int read(char *buf, int size, BIO *table);
/// Return true if the client hello message received and analized
- bool gotHello() {return features.sslVersion != -1;}
+ bool gotHello() { return (helloState == atHelloReceived); }
/// Return the SSL features requested by SSL client
const Bio::sslFeatures &getFeatures() const {return features;}
/// Prevents or allow writting on socket.
class ServerBio: public Bio
{
public:
- explicit ServerBio(const int anFd): Bio(anFd), featuresSet(false), helloMsgSize(0), helloBuild(false), allowSplice(false), allowBump(false), holdWrite_(false), record_(false), bumpMode_(bumpNone) {}
+ explicit ServerBio(const int anFd): Bio(anFd), helloMsgSize(0), helloBuild(false), allowSplice(false), allowBump(false), holdWrite_(false), record_(false), bumpMode_(bumpNone) {}
/// The ServerBio version of the Ssl::Bio::stateChanged method
virtual void stateChanged(const SSL *ssl, int where, int ret);
/// The ServerBio version of the Ssl::Bio::write method
/// Sets the random number to use in client SSL HELLO message
void setClientFeatures(const sslFeatures &features);
+ bool resumingSession();
/// The write hold state
bool holdWrite() const {return holdWrite_;}
/// Enables or disables the write hold state
bool canBump() {return allowBump;}
/// The bumping mode
void mode(Ssl::BumpMode m) {bumpMode_ = m;}
+ Ssl::BumpMode bumpMode() {return bumpMode_;} ///< return the bumping mode
private:
- /// A random number to use as "client random" in client hello message
- sslFeatures clientFeatures;
- bool featuresSet; ///< True if the clientFeatures member is set and can be used
+ sslFeatures clientFeatures; ///< SSL client features extracted from ClientHello message or SSL object
+ sslFeatures serverFeatures; ///< SSL server features extracted from ServerHello message
SBuf helloMsg; ///< Used to buffer output data.
mb_size_t helloMsgSize;
bool helloBuild; ///< True if the client hello message sent to the server
#if _SQUID_WINDOWS_
if (!LockFile(hFile, 0, 0, 1, 0))
-#else
+#elif _SQUID_SOLARIS_
if (lockf(fd, F_LOCK, 0) != 0)
+#else
+ if (flock(fd, LOCK_EX) != 0)
#endif
throw std::runtime_error("Failed to get a lock of " + filename);
}
}
#else
if (fd != -1) {
+#if _SQUID_SOLARIS_
lockf(fd, F_ULOCK, 0);
+#else
+ flock(fd, LOCK_UN);
+#endif
close(fd);
fd = -1;
}
reconfiguring = false;
// remove or change old local storages.
- for (std::map<Ip::Address, LocalContextStorage *>::iterator i = storage.begin(); i != storage.end(); ++i) {
+ for (std::map<Ip::Address, LocalContextStorage *>::iterator i = storage.begin(); i != storage.end();) {
std::map<Ip::Address, size_t>::iterator conf_i = configureStorage.find(i->first);
if (conf_i == configureStorage.end() || conf_i->second <= 0) {
delete i->second;
- storage.erase(i);
+ storage.erase(i++);
} else {
i->second->setMemLimit(conf_i->second);
+ ++i;
}
}
char buffer[256] = "";
SSL *ssl = (SSL *)X509_STORE_CTX_get_ex_data(ctx, SSL_get_ex_data_X509_STORE_CTX_idx());
SSL_CTX *sslctx = SSL_get_SSL_CTX(ssl);
- const char *server = (const char *)SSL_get_ex_data(ssl, ssl_ex_index_server);
+ SBuf *server = (SBuf *)SSL_get_ex_data(ssl, ssl_ex_index_server);
void *dont_verify_domain = SSL_CTX_get_ex_data(sslctx, ssl_ctx_ex_index_dont_verify_domain);
ACLChecklist *check = (ACLChecklist*)SSL_get_ex_data(ssl, ssl_ex_index_cert_error_check);
X509 *peeked_cert = (X509 *)SSL_get_ex_data(ssl, ssl_ex_index_ssl_peeked_cert);
// Check for domain mismatch only if the current certificate is the peer certificate.
if (!dont_verify_domain && server && peer_cert == X509_STORE_CTX_get_current_cert(ctx)) {
- if (!Ssl::checkX509ServerValidity(peer_cert, server)) {
+ if (!Ssl::checkX509ServerValidity(peer_cert, server->c_str())) {
debugs(83, 2, "SQUID_X509_V_ERR_DOMAIN_MISMATCH: Certificate " << buffer << " does not match domainname " << server);
ok = 0;
error_no = SQUID_X509_V_ERR_DOMAIN_MISMATCH;
X509_free(cert);
}
+// "free" function for SBuf
+static void
+ssl_free_SBuf(void *, void *ptr, CRYPTO_EX_DATA *,
+ int, long, void *)
+{
+ SBuf *buf = static_cast <SBuf *>(ptr);
+ delete buf;
+}
+
/// \ingroup ServerProtocolSSLInternal
static void
ssl_initialize(void)
if (!Ssl::DefaultSignHash)
fatalf("Sign hash '%s' is not supported\n", defName);
- ssl_ex_index_server = SSL_get_ex_new_index(0, (void *) "server", NULL, NULL, NULL);
+ ssl_ex_index_server = SSL_get_ex_new_index(0, (void *) "server", NULL, NULL, ssl_free_SBuf);
ssl_ctx_ex_index_dont_verify_domain = SSL_CTX_get_ex_new_index(0, (void *) "dont_verify_domain", NULL, NULL, NULL);
ssl_ex_index_cert_error_check = SSL_get_ex_new_index(0, (void *) "cert_error_check", NULL, &ssl_dupAclChecklist, &ssl_freeAclChecklist);
ssl_ex_index_ssl_error_detail = SSL_get_ex_new_index(0, (void *) "ssl_error_detail", NULL, NULL, &ssl_free_ErrorDetail);
return NULL;
}
+#if defined(TLSEXT_TYPE_next_proto_neg)
+//Dummy next_proto_neg callback
+static int
+ssl_next_proto_cb(SSL *s, unsigned char **out, unsigned char *outlen, const unsigned char *in, unsigned int inlen, void *arg)
+{
+ static const unsigned char supported_protos[] = {8, 'h','t','t', 'p', '/', '1', '.', '1'};
+ (void)SSL_select_next_proto(out, outlen, in, inlen, supported_protos, sizeof(supported_protos));
+ return SSL_TLSEXT_ERR_OK;
+}
+#endif
+
SSL_CTX *
sslCreateClientContext(const char *certfile, const char *keyfile, int version, const char *cipher, const char *options, const char *flags, const char *CAfile, const char *CApath, const char *CRLfile)
{
debugs(83, DBG_IMPORTANT, "WARNING: Ignoring error setting default CA certificate location: " << ERR_error_string(ssl_error, NULL));
}
+#if defined(TLSEXT_TYPE_next_proto_neg)
+ SSL_CTX_set_next_proto_select_cb(sslContext, &ssl_next_proto_cb, NULL);
+#endif
return sslContext;
}
void HttpReply::packHeadersInto(Packable *) const STUB
void HttpReply::reset() STUB
void httpBodyPackInto(const HttpBody *, Packable *) STUB
- bool HttpReply::sanityCheckStartLine(MemBuf *buf, const size_t hdr_len, Http::StatusCode *error) STUB_RETVAL(false)
+ bool HttpReply::sanityCheckStartLine(const char *buf, const size_t hdr_len, Http::StatusCode *error) STUB_RETVAL(false)
int HttpReply::httpMsgParseError() STUB_RETVAL(0)
bool HttpReply::expectingBody(const HttpRequestMethod&, int64_t&) const STUB_RETVAL(false)
bool HttpReply::parseFirstLine(const char *start, const char *end) STUB_RETVAL(false)
HttpRequest::HttpRequest(const HttpRequestMethod& aMethod, AnyP::ProtocolType aProtocol, const char *aUrlpath) : HttpMsg(hoRequest) STUB
HttpRequest::~HttpRequest() STUB
void HttpRequest::packFirstLineInto(Packable *, bool) const STUB
- bool HttpRequest::sanityCheckStartLine(MemBuf *buf, const size_t hdr_len, Http::StatusCode *error) STUB_RETVAL(false)
+ bool HttpRequest::sanityCheckStartLine(const char*buf, const size_t hdr_len, Http::StatusCode *error) STUB_RETVAL(false)
void HttpRequest::hdrCacheInit() STUB
void HttpRequest::reset() STUB
bool HttpRequest::expectingBody(const HttpRequestMethod& unused, int64_t&) const STUB_RETVAL(false)
#endif
int cbdataReferenceValid(const void *p) STUB_RETVAL(0)
-cbdata_type cbdataInternalAddType(cbdata_type type, const char *label, int size, FREE * free_func) STUB_RETVAL(CBDATA_UNKNOWN)
+cbdata_type cbdataInternalAddType(cbdata_type, const char *, int) STUB_RETVAL(CBDATA_UNKNOWN)
*/
#include "squid.h"
+#include "comm/Connection.h"
#define STUB_API "security/libsecurity.la"
#include "tests/STUB.h"
+#include "security/EncryptorAnswer.h"
+Security::EncryptorAnswer::~EncryptorAnswer() {}
+std::ostream &Security::operator <<(std::ostream &os, const Security::EncryptorAnswer &) STUB_RETVAL(os)
+
#include "security/PeerOptions.h"
Security::PeerOptions Security::ProxyOutgoingConfig;
void Security::PeerOptions::parse(char const*) STUB
// a valid status line
input.append("HTTP/1.1 200 Okay\n\n", 19);
hdr_len = headersEnd(input.content(),input.contentSize());
- CPPUNIT_ASSERT( 1 && engine.sanityCheckStartLine(&input, hdr_len, &error) );
+ CPPUNIT_ASSERT( 1 && engine.sanityCheckStartLine(input.content(), hdr_len, &error) );
CPPUNIT_ASSERT_EQUAL(error, Http::scNone);
input.reset();
error = Http::scNone;
input.append("HTTP/1.1 200 Okay \n\n", 28);
hdr_len = headersEnd(input.content(),input.contentSize());
- CPPUNIT_ASSERT( 2 && engine.sanityCheckStartLine(&input, hdr_len, &error) );
+ CPPUNIT_ASSERT( 2 && engine.sanityCheckStartLine(input.content(), hdr_len, &error) );
CPPUNIT_ASSERT_EQUAL(error, Http::scNone);
input.reset();
error = Http::scNone;
// invalid status line
input.append("HTTP/1.1 999 Okay\n\n", 19);
hdr_len = headersEnd(input.content(),input.contentSize());
- CPPUNIT_ASSERT( 3 && !engine.sanityCheckStartLine(&input, hdr_len, &error) );
+ CPPUNIT_ASSERT( 3 && !engine.sanityCheckStartLine(input.content(), hdr_len, &error) );
CPPUNIT_ASSERT_EQUAL(error, Http::scInvalidHeader);
input.reset();
error = Http::scNone;
input.append("HTTP/1.1 2000 Okay \n\n", 29);
hdr_len = headersEnd(input.content(),input.contentSize());
- CPPUNIT_ASSERT( 4 && engine.sanityCheckStartLine(&input, hdr_len, &error) );
+ CPPUNIT_ASSERT( 4 && engine.sanityCheckStartLine(input.content(), hdr_len, &error) );
CPPUNIT_ASSERT_EQUAL(error, Http::scNone);
input.reset();
error = Http::scNone;
// valid ICY protocol status line
input.append("ICY 200 Okay\n\n", 14);
hdr_len = headersEnd(input.content(),input.contentSize());
- CPPUNIT_ASSERT( engine.sanityCheckStartLine(&input, hdr_len, &error) );
+ CPPUNIT_ASSERT( engine.sanityCheckStartLine(input.content(), hdr_len, &error) );
CPPUNIT_ASSERT_EQUAL(error, Http::scNone);
input.reset();
error = Http::scNone;
// empty status line
input.append("\n\n", 2);
hdr_len = headersEnd(input.content(),input.contentSize());
- CPPUNIT_ASSERT( 5 && !engine.sanityCheckStartLine(&input, hdr_len, &error) );
+ CPPUNIT_ASSERT( 5 && !engine.sanityCheckStartLine(input.content(), hdr_len, &error) );
CPPUNIT_ASSERT_EQUAL(error, Http::scInvalidHeader);
input.reset();
error = Http::scNone;
input.append(" \n\n", 8);
hdr_len = headersEnd(input.content(),input.contentSize());
- CPPUNIT_ASSERT( 6 && !engine.sanityCheckStartLine(&input, hdr_len, &error) );
+ CPPUNIT_ASSERT( 6 && !engine.sanityCheckStartLine(input.content(), hdr_len, &error) );
CPPUNIT_ASSERT_EQUAL(error, Http::scInvalidHeader);
input.reset();
error = Http::scNone;
// status line with no message
input.append("HTTP/1.1 200\n\n", 14); /* real case seen */
hdr_len = headersEnd(input.content(),input.contentSize());
- CPPUNIT_ASSERT(engine.sanityCheckStartLine(&input, hdr_len, &error) );
+ CPPUNIT_ASSERT(engine.sanityCheckStartLine(input.content(), hdr_len, &error) );
CPPUNIT_ASSERT_EQUAL(error, Http::scNone);
input.reset();
error = Http::scNone;
input.append("HTTP/1.1 200 \n\n", 15); /* real case seen */
hdr_len = headersEnd(input.content(),input.contentSize());
- CPPUNIT_ASSERT(engine.sanityCheckStartLine(&input, hdr_len, &error) );
+ CPPUNIT_ASSERT(engine.sanityCheckStartLine(input.content(), hdr_len, &error) );
CPPUNIT_ASSERT_EQUAL(error, Http::scNone);
input.reset();
error = Http::scNone;
// incomplete (short) status lines... not sane (yet), but no error either.
input.append("H", 1);
hdr_len = headersEnd(input.content(),input.contentSize());
- CPPUNIT_ASSERT(!engine.sanityCheckStartLine(&input, hdr_len, &error) );
+ CPPUNIT_ASSERT(!engine.sanityCheckStartLine(input.content(), hdr_len, &error) );
CPPUNIT_ASSERT_EQUAL(error, Http::scNone);
input.reset();
error = Http::scNone;
input.append("HTTP/", 5);
hdr_len = headersEnd(input.content(),input.contentSize());
- CPPUNIT_ASSERT(!engine.sanityCheckStartLine(&input, hdr_len, &error) );
+ CPPUNIT_ASSERT(!engine.sanityCheckStartLine(input.content(), hdr_len, &error) );
CPPUNIT_ASSERT_EQUAL(error, Http::scNone);
input.reset();
error = Http::scNone;
input.append("HTTP/1", 6);
hdr_len = headersEnd(input.content(),input.contentSize());
- CPPUNIT_ASSERT(!engine.sanityCheckStartLine(&input, hdr_len, &error) );
+ CPPUNIT_ASSERT(!engine.sanityCheckStartLine(input.content(), hdr_len, &error) );
CPPUNIT_ASSERT_EQUAL(error, Http::scNone);
input.reset();
error = Http::scNone;
input.append("HTTP/1.1", 8);
hdr_len = headersEnd(input.content(),input.contentSize());
- CPPUNIT_ASSERT(!engine.sanityCheckStartLine(&input, hdr_len, &error) );
+ CPPUNIT_ASSERT(!engine.sanityCheckStartLine(input.content(), hdr_len, &error) );
CPPUNIT_ASSERT_EQUAL(error, Http::scNone);
input.reset();
error = Http::scNone;
input.append("HTTP/1.1 ", 9); /* real case seen */
hdr_len = headersEnd(input.content(),input.contentSize());
- CPPUNIT_ASSERT(engine.sanityCheckStartLine(&input, hdr_len, &error) );
+ CPPUNIT_ASSERT(!engine.sanityCheckStartLine(input.content(), hdr_len, &error) );
CPPUNIT_ASSERT_EQUAL(error, Http::scNone);
input.reset();
error = Http::scNone;
input.append("HTTP/1.1 20", 14);
hdr_len = headersEnd(input.content(),input.contentSize());
- CPPUNIT_ASSERT(engine.sanityCheckStartLine(&input, hdr_len, &error) );
+ CPPUNIT_ASSERT(!engine.sanityCheckStartLine(input.content(), hdr_len, &error) );
CPPUNIT_ASSERT_EQUAL(error, Http::scNone);
input.reset();
error = Http::scNone;
// status line with no status
input.append("HTTP/1.1 \n\n", 11);
hdr_len = headersEnd(input.content(),input.contentSize());
- CPPUNIT_ASSERT(!engine.sanityCheckStartLine(&input, hdr_len, &error) );
+ CPPUNIT_ASSERT(!engine.sanityCheckStartLine(input.content(), hdr_len, &error) );
CPPUNIT_ASSERT_EQUAL(error, Http::scInvalidHeader);
input.reset();
error = Http::scNone;
input.append("HTTP/1.1 \n\n", 15);
hdr_len = headersEnd(input.content(),input.contentSize());
- CPPUNIT_ASSERT(!engine.sanityCheckStartLine(&input, hdr_len, &error) );
+ CPPUNIT_ASSERT(!engine.sanityCheckStartLine(input.content(), hdr_len, &error) );
CPPUNIT_ASSERT_EQUAL(error, Http::scInvalidHeader);
input.reset();
error = Http::scNone;
input.append("HTTP/1.1 Okay\n\n", 16); /* real case seen */
hdr_len = headersEnd(input.content(),input.contentSize());
- CPPUNIT_ASSERT(!engine.sanityCheckStartLine(&input, hdr_len, &error) );
+ CPPUNIT_ASSERT(!engine.sanityCheckStartLine(input.content(), hdr_len, &error) );
CPPUNIT_ASSERT_EQUAL(error, Http::scInvalidHeader);
input.reset();
error = Http::scNone;
// status line with nul-byte
input.append("HTTP/1.1" "\0" "200 Okay\n\n", 19); /* real case seen */
hdr_len = headersEnd(input.content(),input.contentSize());
- CPPUNIT_ASSERT(!engine.sanityCheckStartLine(&input, hdr_len, &error) );
+ CPPUNIT_ASSERT(!engine.sanityCheckStartLine(input.content(), hdr_len, &error) );
CPPUNIT_ASSERT_EQUAL(error, Http::scInvalidHeader);
input.reset();
error = Http::scNone;
// status line with negative status
input.append("HTTP/1.1 -000\n\n", 15); /* real case seen */
hdr_len = headersEnd(input.content(),input.contentSize());
- CPPUNIT_ASSERT(!engine.sanityCheckStartLine(&input, hdr_len, &error) );
+ CPPUNIT_ASSERT(!engine.sanityCheckStartLine(input.content(), hdr_len, &error) );
CPPUNIT_ASSERT_EQUAL(error, Http::scInvalidHeader);
input.reset();
error = Http::scNone;
class PrivateHttpRequest : public HttpRequest
{
public:
- bool doSanityCheckStartLine(MemBuf *b, const size_t h, Http::StatusCode *e) { return sanityCheckStartLine(b,h,e); };
+ bool doSanityCheckStartLine(const char *b, const size_t h, Http::StatusCode *e) { return sanityCheckStartLine(b,h,e); };
};
/* init memory pools */
// a valid request line
input.append("GET / HTTP/1.1\n\n", 16);
hdr_len = headersEnd(input.content(), input.contentSize());
- CPPUNIT_ASSERT(engine.doSanityCheckStartLine(&input, hdr_len, &error) );
+ CPPUNIT_ASSERT(engine.doSanityCheckStartLine(input.content(), hdr_len, &error) );
CPPUNIT_ASSERT_EQUAL(error, Http::scNone);
input.reset();
error = Http::scNone;
input.append("GET / HTTP/1.1\n\n", 18);
hdr_len = headersEnd(input.content(), input.contentSize());
- CPPUNIT_ASSERT(engine.doSanityCheckStartLine(&input, hdr_len, &error) );
+ CPPUNIT_ASSERT(engine.doSanityCheckStartLine(input.content(), hdr_len, &error) );
CPPUNIT_ASSERT_EQUAL(error, Http::scNone);
input.reset();
error = Http::scNone;
// strange but valid methods
input.append(". / HTTP/1.1\n\n", 14);
hdr_len = headersEnd(input.content(), input.contentSize());
- CPPUNIT_ASSERT(engine.doSanityCheckStartLine(&input, hdr_len, &error) );
+ CPPUNIT_ASSERT(engine.doSanityCheckStartLine(input.content(), hdr_len, &error) );
CPPUNIT_ASSERT_EQUAL(error, Http::scNone);
input.reset();
error = Http::scNone;
input.append("OPTIONS * HTTP/1.1\n\n", 20);
hdr_len = headersEnd(input.content(), input.contentSize());
- CPPUNIT_ASSERT(engine.doSanityCheckStartLine(&input, hdr_len, &error) );
+ CPPUNIT_ASSERT(engine.doSanityCheckStartLine(input.content(), hdr_len, &error) );
CPPUNIT_ASSERT_EQUAL(error, Http::scNone);
input.reset();
error = Http::scNone;
input.append(" \n\n", 8);
hdr_len = headersEnd(input.content(), input.contentSize());
- CPPUNIT_ASSERT(!engine.doSanityCheckStartLine(&input, hdr_len, &error) );
+ CPPUNIT_ASSERT(!engine.doSanityCheckStartLine(input.content(), hdr_len, &error) );
CPPUNIT_ASSERT_EQUAL(error, Http::scInvalidHeader);
input.reset();
error = Http::scNone;
#include "ssl/bio.h"
#include "ssl/PeerConnector.h"
#include "ssl/ServerBump.h"
+#else
+#include "security/EncryptorAnswer.h"
#endif
#include "tools.h"
#if USE_DELAY_POOLS
class MyAnswerDialer: public CallDialer, public Ssl::PeerConnector::CbDialer
{
public:
- typedef void (TunnelStateData::*Method)(Ssl::PeerConnectorAnswer &);
+ typedef void (TunnelStateData::*Method)(Security::EncryptorAnswer &);
MyAnswerDialer(Method method, TunnelStateData *tunnel):
method_(method), tunnel_(tunnel), answer_() {}
}
/* Ssl::PeerConnector::CbDialer API */
- virtual Ssl::PeerConnectorAnswer &answer() { return answer_; }
+ virtual Security::EncryptorAnswer &answer() { return answer_; }
private:
Method method_;
CbcPointer<TunnelStateData> tunnel_;
- Ssl::PeerConnectorAnswer answer_;
+ Security::EncryptorAnswer answer_;
};
-
- void connectedToPeer(Ssl::PeerConnectorAnswer &answer);
#endif
+ /// callback handler after connection setup (including any encryption)
+ void connectedToPeer(Security::EncryptorAnswer &answer);
+
public:
bool keepGoingAfterRead(size_t len, Comm::Flag errcode, int xerrno, Connection &from, Connection &to);
void copy(size_t len, Connection &from, Connection &to, IOCB *);
HttpReply rep;
Http::StatusCode parseErr = Http::scNone;
const bool eof = !chunkSize;
- const bool parsed = rep.parse(connectRespBuf, eof, &parseErr);
+ connectRespBuf->terminate(); // HttpMsg::parse requires terminated string
+ const bool parsed = rep.parse(connectRespBuf->content(), connectRespBuf->contentSize(), eof, &parseErr);
if (!parsed) {
if (parseErr > 0) { // unrecoverable parsing error
server.logicError("malformed CONNECT response from peer");
{
if (!data)
return;
+
TunnelStateData *tunnel = static_cast<TunnelStateData*>(data);
- if (!tunnel)
- return;
tunnel->client.readPending = NULL;
static uint64_t counter=0;
debugs(26, 7, "Client read(2) delayed " << ++counter << " times");
{
if (!data)
return;
+
TunnelStateData *tunnel = static_cast<TunnelStateData*>(data);
- if (!tunnel)
- return;
tunnel->server.readPending = NULL;
static uint64_t counter=0;
debugs(26, 7, "Server read(2) delayed " << ++counter << " times");
void
TunnelStateData::connectToPeer()
{
- const Comm::ConnectionPointer &srv = server.conn;
-
#if USE_OPENSSL
- if (CachePeer *p = srv->getPeer()) {
+ if (CachePeer *p = server.conn->getPeer()) {
if (p->secure.encryptTransport) {
AsyncCall::Pointer callback = asyncCall(5,4,
"TunnelStateData::ConnectedToPeer",
MyAnswerDialer(&TunnelStateData::connectedToPeer, this));
Ssl::PeerConnector *connector =
- new Ssl::PeerConnector(request, srv, client.conn, callback);
+ new Ssl::PeerConnector(request, server.conn, client.conn, callback);
AsyncJob::Start(connector); // will call our callback
return;
}
}
#endif
- tunnelRelayConnectRequest(srv, this);
+ Security::EncryptorAnswer nil;
+ connectedToPeer(nil);
}
-#if USE_OPENSSL
-/// Ssl::PeerConnector callback
void
-TunnelStateData::connectedToPeer(Ssl::PeerConnectorAnswer &answer)
+TunnelStateData::connectedToPeer(Security::EncryptorAnswer &answer)
{
if (ErrorState *error = answer.error.get()) {
*status_ptr = error->httpStatus;
tunnelRelayConnectRequest(server.conn, this);
}
-#endif
static void
tunnelRelayConnectRequest(const Comm::ConnectionPointer &srv, void *data)
return (urlbuf);
}
-/*
- * matchDomainName() compares a hostname with a domainname according
- * to the following rules:
- *
- * HOST DOMAIN MATCH?
- * ------------- ------------- ------
- * foo.com foo.com YES
- * .foo.com foo.com YES
- * x.foo.com foo.com NO
- * foo.com .foo.com YES
- * .foo.com .foo.com YES
- * x.foo.com .foo.com YES
- *
- * We strip leading dots on hosts (but not domains!) so that
- * ".foo.com" is is always the same as "foo.com".
- *
- * Return values:
- * 0 means the host matches the domain
- * 1 means the host is greater than the domain
- * -1 means the host is less than the domain
- */
-
int
-matchDomainName(const char *h, const char *d)
+matchDomainName(const char *h, const char *d, bool honorWildcards)
{
int dl;
int hl;
/*
* We found different characters in the same position (from the end).
*/
+
+ // If the h has a form of "*.foo.com" and d has a form of "x.foo.com"
+ // then the h[hl] points to '*', h[hl+1] to '.' and d[dl] to 'x'
+ // The following checks are safe, the "h[hl + 1]" in the worst case is '\0'.
+ if (honorWildcards && h[hl] == '*' && h[hl + 1] == '.')
+ return 0;
+
/*
* If one of those character is '.' then its special. In order
* for splay tree sorting to work properly, "x-foo.com" must
#define _SQUID_TOOLS_SQUIDCLIENT_GSSAPI_H
#if HAVE_GSSAPI
+#if USE_APPLE_KRB5
+#define GSSKRB_APPLE_DEPRECATED(x)
+#endif
#if USE_HEIMDAL_KRB5
#if HAVE_GSSAPI_GSSAPI_H