universidade ibirapuera curso de ciência da computação

Transcrição

universidade ibirapuera curso de ciência da computação
UNIVERSIDADE IBIRAPUERA
CURSO DE CIÊNCIA DA COMPUTAÇÃO
PROJETO SQUID
Trabalho apresentado à Universidade
Ibirapuera para obtenção do título de
Bacharel em Ciência da Computação
Cristiano F. Reis – 574132
Gerson Raimundo – 608415
Gilberto T. Do Carmo – 568508
São Paulo
2006
Dedicatória
Este trabalho foi desenvolvimento em conjunto de três bons amigos de
faculdade que se conheceram e tornaram-se bom amigos, e dedicam todo o seu conteúdo
para os seus Familiares.
Agradecimentos
Agradecemos ao nosso querido orientador Cristiano Toniolo e Fabio Cabrini que
nos indicou o melhor caminho a ser seguido, e colocou a disposição toda a sua atenção e
a toda comunidade Linux que desenvolveu este grande projeto.
Resumo
Este trabalho apresenta um estudo a respeito dos servidores Proxy, e do
desempenho do Squid, um servidor Proxy Livre, que possui características que o tornam
um dos melhores. É feito um detalhamento a respeito de sua implementação e como ele é
usado como servidor de Proxy e sistemas para esta finalidade.
Apesar das operações do mesmo, (contém um problema em especifico que é o seu
desempenho no recebimento de um número elevado de requisições). Este é o objetivo
deste trabalho, onde apresentamos soluções para a resolução desta deficiência.
Palavras-Chaves:
Proxy, Squid, algoritmos de ordenação e busca.
Abstract
This work presents a study regarding the Proxy servers, in of the performance of
the Squid, Free a Proxy server, that possesss characteristics that become it one of the
best ones. A detailing regarding its implementation is made and as it is used as serving of
Proxy and systems for this purpose.
Despite the operations of exactly, (it contains a
problem in I specify that it is its performance in the act of receiving of a high number of
solicitations). This is the objective of this work, where we present solutions for the
resolution of this deficiency.
Keywords:
Proxy, Squid, algorithms of ordinance and search.
Sumário
1 – Introdução...................................................................................................................................01
1.1 – Objetivo........................................................................................................................... 03
1.2 – Estrutura......................................................................................................................... .03
Capítulo 2 – Proxy........................................................................................................................... 04
2.1 - Origem do Proxy.............................................................................. …............................04
2.2 - Tipos de Proxy.............................................................................................................. .05
2.2.1 – Squid......................................................................................................................... .06
2.2.2 - Delegate............................................................................... …...................................07
2.2.3 – Oops.......................................................................................................................... .08
2.2.4 – Dansguardian............................................................................................................ .09
2.3 - Principais Características dos Proxy............................................................................. .10
2.3.1
- Proxy Transparente................................................................................................. .10
2.3.2
- Proxy Controlado.................................................................................................... 11
2.4 - Proxy Transparente X Proxy Controlado...................................................................... 11
2.5 2.4.1 - Vantagens do Proxy Transparente........................................................................ 11
2.4.2 - Desvantagens do Proxy Transparente................................. …...................................12
2.4.3 - Vantagens do Proxy Controlado................................................................................. 13
2.4.4 - Desvantagens do Proxy Controlado........................................................................... 13
2.5 - Arquitetura do Proxy..................................................................................................... 13
2.5.1 – Cache......................................................................................................................... 13
2.5.2 – Autenticação.............................................................................................................. 14
2.5.3 - Listas de controles de acesso.............................................. …...................................14
2.5.4 - Proxy para SSL........................................................................................................... 14
Capítulo 3 – Squid........................................................................................................................... 15
3.1 - Características do Proxy Squid..................................................................................... 16
3.1.1 - Restrições de acesso........................................................... …....................................16
3.1.2 - Arquivo de configuração............................................................................................ 18
3.1.3 - Função do Proxy squid............................................................................................... 18
3.1.4 - Progresso do Squid..................................................................................................... 19
3.1.5 - Tipos de protocolos.................................................................................................... 19
3.1.6 - Proxy transparente no Squid...................................................................................... 19
3.1.7 - Listas de controle de acesso....................................................................................... 20
3.2 - Squid como servidor...................................................................................................... 24
3.3 - Estrutura de Hardware..................................................................... …..........................25
3.4 – Tags............................................................................................................................... 26
3.5 - Referências de conexão................................................................................................. 26
3.6 – Vantagens...................................................................................................................... 28
Capítulo 4 - Conhecendo Algumas Soluções................................................................................. 29
4.1 – Configuração................................................................................................................... 29
4.2 – Hdparm........................................................................................................................... 29
4.3 - Banco de Dados............................................................................................................... 29
4.4 - Alteração do Código fonte............................................................................................... 30
4.5 - Compilação do Kernel..................................................................................................... 30
Capítulo 5 - Aplicando a solução escolhida................................................. …..............................31
5.1 - A Escolha......................................................................................................................... 31
5.2 - Desenvolvendo a Solução................................................................ …............................31
5.3 - Detalhamento do processo............................................................................................... 32
5.4 - Introdução ao Perl......................................................................................................... 34
5.4.1 - Características do Perl...................................................................................... 35
5.5 - Introdução ao PostgreSQL.............................................................................................36
5.6 - Outras soluções aplicadas.............................................................................................. 37
5.6.1 - HDparm................................................................................ ….........................37
5.6.2 – Kernel............................................................................................................. 39
Capítulo 6 – Conclusão....................................................................................................................42
Lista de anexos................................................................................................................................. 43
Referências....................................................................................................................................... 49
1 - Introdução
A popularização da Web1 tem provocado sérios problemas de desempenho nos acessos à
Internet, de forma que a redução do tempo tem se tornado um fator extremamente relevante. O
número de usuários que se conectam na rede cresce de forma acentuada.
O tempo para se recuperar um documento Web depende de determinados fatores (tipo de
conexão, tamanho do documento, localização do mesmo). Para minimizar as conseqüências deste
crescimento, alguns métodos podem ser adotados como a utilização de um servidor mais rápido,
alteração dos meios físicos (Cabos, Roteadores, Switches, etc.) de forma que se aumente a banda.
Contudo, isto além de não ser economicamente viável, pode não resolver o problema, uma vez que
são numerosos os fatores que envolvem uma única transação Web. Alternativas como o cache de
páginas Web, espelhamento de arquivos entre outros têm sido aplicados para resolver determinadas
situações inerentes à rede.
O procedimento de implantação de um sistema de cache de navegação que armazene
localmente objetos como páginas HTML2 (HyperText Markup Language), imagens e arquivos da
Internet, podem melhorar a qualidade do serviço fornecido aos usuários. Os servidores de Proxy
ajudam a diminuir de forma significativa o tempo médio de acesso a páginas e a transferência de
arquivos, porque muitos deles (páginas Web, arquivos, fotos, etc.) são requisitados mais de uma
vez, entretanto, exceto na primeira vez estas requisições são feitas remotamente, ou seja, as páginas
são carregadas direto do servidor que estão hospedadas, caso contrário às requisições são atendidas
de forma local.
1
Web: Rede de computadores na Internet que fornece informação em forma de hipertexto.
HTML: É um dispositivo de acesso rápido, interno a um sistema, que serve de intermediário entre um operador de um
processo e o dispositivo de armazenamento.
2
De uma forma geral os visualizadores de páginas Web conhecidos como browsers fazem
conexão direta com os servidores remotos. Entretanto, eles podem ser configurados para se conectar
a um servidor Proxy.
Assim, quando um usuário requisitar uma página, o browser primeiramente verifica seu cache
local. Se a página URL1 não é encontrada, ele a requisita para o servidor Proxy local. Se este tém a
cópia e ela não expirou, ele a retorna imediatamente, caracterizando desta forma o conceito de
cache hit. Caso esta não esteja no cache, ele entrará em contato com o servidor remoto e fará a
transferência, mantendo uma cópia opcional em seu cache e enviando uma cópia para a máquina do
usuário, neste caso, haverá o que chamamos de conceito cache miss.
Uma das funções do Proxy é denominada de Filtro. Este filtro é usado para permitir ou negar
o acesso à Internet ou a determinados sites, ou seja, controle de conteúdo. Administradores podem
criar regras conforme suas políticas de segurança para filtrar requisições baseadas no endereço IP 2
(Internet Protocol) do cliente, domínios, redes e URL do objeto requisitado, bloqueando assim
requisições consideradas impróprias a política adotada. Tais funcionalidades são usadas
principalmente em escolas e em organizações que utilizam o critério de permissão para o acesso a
páginas que realmente sejam de seu interesse. O filtro podem conter regras simples baseados em
uma lista de páginas Web, bem como conter regras mais complexas.
1
2
URL: É o endereço de um recurso, disponível em uma rede; seja a Internet, ou uma rede corporativa ou uma intranet.
IP: É um protocolo usado entre duas máquinas em rede para encaminhamento dos dados.
1.1 - Objetivo
O objetivo deste trabalho é a implementação e a otimização do Proxy Squid que apesar de
funcionar de uma forma completa e atender determinadas necessidades apresenta um fator
relevante, que é o seu desempenho quanto ao processamento de requisições ACL 1 (Access Control
List). O seu desempenho se torna crítico quando a quantidade de usuários conectados ao Proxy é
grande e ao carregar uma black-list muito grande que leva ele a travar, a partir desta quantidade ele
passa a consumir um valor considerável de memória, e para compensar tal situação, é necessário
disponibilizar um computador mais potente o que acaba onerando os custos significativamente, pois
a cada demanda de processos é necessário ajustar o hardware.
O Squid possue esta deficiência, o que estamos propondo é minimizar esta situação aplicando
soluções que são a melhora do programa do Squid como um front-end ideal para a solução e
também melhorando a entrada e saída do disco rígido, e aplicando uma configuração ideal para o
hardware diretamente no kernel influenciando diretamente no desempenho do mesmo e diminuindo
a sobrecarga da memória efetuada durante o trabalho do Proxy.
1.2 - Estrutura
Para atingir este objetivo o trabalho foi estruturado da seguinte forma:
•
•
•
•
1
Capítulo 2: Proxy;
Capítulo 3: Squid;
Capítulo 4: Conhecendo algumas possíveis soluções;
Capítulo 5: Aplicando a solução escolhida.
ACL: É normalmente uma lista de princípios com os tipos de acesso definido para cada usuário ou grupo.
Capítulo 2 - Proxy
2.1 - Origem do Proxy
O Proxy surgiu da necessidade de conectar uma rede local à Internet através de um
computador da rede que compartilha sua conexão com as máquinas da rede. Conforme Peter
(Thoeny 2002), se considerarmos que a rede local é uma rede interna e a Internet é uma rede
externa, podemos dizer que o Proxy é quem permite que outras máquinas tenham acesso externo, ou
seja, a conexão com a Internet.
Geralmente, máquinas da rede interna não possuem endereços válidos na Internet, primeiro
pelo fato da segurança nas redes privadas e também devido à falta de IP’s válidos, portanto, não têm
uma conexão direta com a Internet. Assim, toda solicitação de conexão de uma máquina da rede
local para um host da Internet é direcionada ao Proxy, este, por sua vez, realiza o contato com o host
desejado, repassando a resposta da solicitação para a máquina da rede local.
É comum termos o Proxy como conexão direta com a Internet. Vejamos um exemplo de um
esquema de servidor Proxy. Figura 1.
Figura 1 - Compartilhamento de Internet utilizando Proxy (Reis, 2006).
2.2 - Tipos de Proxy
Existem vários softwares diferentes com as características de Proxy, alguns mais
especializados em somente alguns protocolos, outros com mais funcionalidades, como filtragem de
controle de conteúdo e firewall, outros mais especializados em otimização de cache em RAM 1 ou
disco rígido.
Dentre os vários Proxy existentes para o sistema operacional Linux, com pelo menos suporte
à HTTP2, HTTPS3 e FTP4, conforme citado por Peter Thoeny (2002) destaca-se Squid, Delegate,
Dansguardian, Oops entre outros.
1
RAM: Randomic Access Memory
HTTP: É um protocolo da camada de "Aplicação" do modelo OSI, utilizado para transferência de dados na Internet.
3
HTTPS: É um protocolo da camada de "Aplicação" do modelo OSI, com implementação de segurança.
4
FTP: É uma forma bastante rápida e versátil de transferir arquivos, sendo uma das mais usadas na internet.
2
2.2.1 - Squid
Foi originado de um projeto denominado Harvest entre o governo americano e a
Universidade de Colorado. Atualmente é o Proxy mais popular e mais usado como controle de
conteúdo, na qual possui vários programadores como desenvolvedores do projeto pelo mundo.
É geralmente disponibilizado por padrão pela maioria dos sistemas operacionais Linux,
fornecendo todas as funcionalidades de um Proxy comum.
Permite atuar como Proxy para os protocolos HTTPS, HTTP, FTP e Gopher 1. Para outros
protocolos como correio eletrônico (SMTP2 e POP3) e ICQ4.
1
Gopher: É um protocolo de redes de computadores que foi desenhado para indexar repositórios de documentos na
Internet.
2
SMTP: É o padrão de fato para envio de e-mail através da Internet.
3
POP: É um protocolo utilizado no acesso remoto a uma caixa de correio eletrônico.
4
ICQ: É um programa de comunicação instantânea pela Internet.
2.2.2 - Delegate
Este também é um Proxy interessante, de autoria de Yutaka Sato (2006), o Delegate é um
Proxy Server 5multiplataforma com relays e vários protocolos de aplicação em TCP/IP ou em
UDP/IP, incluindo o HTTP, FTP, Telnet1, NNTP2, SMTP3, IMAP4, LPR5, LDAP6, ICP7, DNS8, SSL9
e Socks10. O Delegate interliga uma comunicação entre usuários e clientes, onde uma comunicação
direta é impossível, ineficiente, ou inconveniente, conforme Sato (2006).
1
Telnet: É um protocolo cliente-servidor de comunicações usado para permitir a comunicação entre computadores
ligados numa rede, baseado em TCP.
2
NNTP: É um protocolo da internet para grupos de discussão da chamada usenet.
3
SMTP: é um protocolo relativamente simples, baseado em texto simples, em que um ou vários destinatários de uma
mensagem são especificados, sendo depois a mensagem transferida.
4
IMAP: É um protocolo de gerenciamento de correio eletrônico superior em recursos ao POP3
5
LPR: É a porta de impressão em Linux.
6
LDAP: Serviço de rede que disponibiliza integração de senhas para qualquer serviço.
7
ICP: Uma Infra-Estrutura de Chaves Públicas é um órgão ou inciativa pública ou privada para a organização de uma
estrutura de emissão de chaves públicas.
8
DNS: É um sistema de gerenciamento de nomes hierárquico.
9
SSL: É um protocolo criptográfico que provêem comunicação segura na Internet para coisas como e-mail, navegação
por páginas, e outros tipos de transferência de dados
10
Socks: é um protocolo de internet que permite que aplicações cliente-servidor usem transparentemente o serviço de
uma rede ao firewall.
2.2.3 - Oops
É um Proxy mais simples que os anteriores. Surgiu como uma alternativa ao Squid. Oops é
leve, embora, trata-se de um poderoso Proxy com cache. Suas principais características conforme
(Cipriano 2006), é:
• HTTP/1.1 (ainda sem conexões persistentes) e FTP;
• Ele está pronto para servir pedidos imediatamente após iniciado;
• Armazenamentos em disco são checados em segundo plano, enquanto servem pedidos
diretamente da rede;
• Reconfiguração limpa em Sighup1 e sem sessões quebradas, novas configurações
aplicadas a novas conexões;
• Arquivo de configuração e ACL’s fáceis de ler e entender;
• Controle de largura de banda;
• Diversos tipos de módulos existem como geração de logs, acesso, saída, relato de
erros, filtragem de URL, etc;
• Objetos são armazenados em arquivos grandes e sem esquema de objeto por arquivo.
Esses arquivos grandes podem ser dispositivos como (/dev/hda).
1
Sighup: Define-se como a reinicialização de um processo sem a necessidade de reiniciar a máquina.
2.2.4 - Dansguardian
É uma ferramenta capaz de filtrar acessos a Internet com base em diferentes critérios, possui
filtros com as seguintes características, conforme descrito por Silva (2006).
• Filtros de domínios ou URL’s com um desempenho visivelmente superior a outras
ferramentas;
• Filtros baseados em frases associadas à pornografia ou consideradas inapropriadas;
• Filtros por figuras ou por tipo de conteúdos (MIME1);
• Filtros por extensão de arquivos, como: .exe, .dll, .scr, etc;
• Filtro com caractrísticas em que é possível bloquear ou limitar upload na Internet.
A ferramenta difere da maioria disponível no mercado pelo fato de não funcionar apenas
como filtro de URL, mas também como um efetivo filtro de conteúdos de páginas Web. Pois, faz
uma varredura do conteúdo de cada página acessada por seus usuários e não somente uma liberação
ou proibição do nome do site ou da URL acessada.
Este filtro de conteúdo funciona em conjunto com qualquer Proxy, podendo ser instalado em
sistemas operacionais Linux, FreeBSD, OpenBSD, NetBSD, Mac OSX e Solaris.
O Dansguardian não tem características de Proxy, portanto é obrigatório o uso de um
servidor Proxy para que a ferramenta seja implementada, embora ele tenha sido citado neste
trabalho por ser relevante suas funções.
Nas soluções comumente encontradas no mercado, o filtro de conteúdo recebe as requisições
do navegador do usuário, aplica as restrições estabelecidas ou as exceções configuradas e, em
seguida, passa a requisição para o Proxy.
Este faz o seu papel que é a intermediação entre o cliente e o servidor a ser acessado. No
processamento interno de arquivos contendo proibições e exceções, existe uma ordem préestabelecida.
1
MIME: É uma norma da Internet para o formato das mensagens de correio eletrônico .
Apesar do Dansguardian não ter características de Proxy o mesmo foi citado apenas para fim
de conhecimento, uma vez que o objetivo deste trabalho é demonstrar os diversos tipos de
aplicações para otimização do Proxy Squid, procurando a melhor solução para desempenho do
mesmo tornando-o tão eficiente quanto o Dansguardian no processo de filtro de conteúdos, pois
quando o Squid utiliza uma base muito extensa (Black-list1), consequentemente passa a utilizar
muita memória e se torna lento demais sobrecarregando consideravelmente a rede.
2.3 - Principais Características dos Proxy
Um exemplo muito comum de compartilhamento de Internet é baseado em um servidor
Proxy com duas interfaces de rede, geralmente um modem e uma interface Ethernet, sendo que a
interface do modem é a interface de saída para Internet, enquanto a interface de rede, é a interface
de acesso às máquinas da rede local. O compartilhamento de Internet apresentado se refere ao
serviço básico de um Proxy. Mas um bom Proxy deve ainda prover várias outras funcionalidades
complementares conforme Peter Thoeny (2002).
Existem duas características principais de Proxy, na qual são definidos, como Proxy
Transparente e Proxy Controlado, conforme Martins (2006).
2.3.1 - Proxy Transparente
Nele é simplesmente feito um encaminhamento de pacotes vindos da Internet para uma
máquina que esta na rede interna. Com o Proxy transparente não é preciso configurar o navegador
como por exemplo o Internet Explorer ou o Firefox, facilitando a administração da rede. Isto é
realizado através de configurações no roteador ou no firewall padrão da rede local, de forma que
toda solicitação de tráfego externo é direcionada para o Proxy. Assim, o Proxy funciona de forma
transparente para o usuário, sem necessidade de configuração.
1
Black-list: Arquivo contendo nome de sites proibidos.
2.3.2 - Proxy Controlado
Esta é uma característica dos softwares especializados em agir como servidores Proxy, como
o próprio Squid. Eles possuem certas opções que o Proxy Transparente para facilitar o controle de
quem pode ou não utilizar o Proxy, e a sua configuração deve estar como padrão em todos os
browser com o IP do servidor Proxy. Conforme Thoeny (2002), com ele também é possível
implementar o controle de conteúdo com base em ACL (Access Control List), ou seja listas de
acesso previamente definidas.
2.4 - Proxy Transparente X Proxy Controlado
Vantagens e desvantagens estão relacionadas com o seu tipo de caso, onde em uma situação
hipotética você poderá ter uma empresa em que os administradores preferem colocar o IP do Proxy
em cada máquina e também pode acontecer que em certos casos o administrador de departamento
de informática deseja não colocar nenhuma informação nos navegadores dos usuários, como um
administrador de rede, vai ter que decidir qual tipo de Proxy utilizar e qual o melhor para a situação,
vão existir casos em que um Proxy Transparente vai oferecer o suficiente para as regras de certa
empresa e vão existir casos em que irão ser necessário as funções que somente um Proxy controlado
pode oferecer.
2.4.1 - Vantagens do Proxy Transparente
É mais simples de ser configurado quando já está habilitado no Kernel, quando não está
habilitado no kernel o mesmo deve ser reinstalado com o suporte ativo para que seja usado.
Programas como ICQ funcionam plenamente com ele e não precisa que as máquinas clientes sejam
configuradas. Afinal de contas, qual é a idéia de Proxy transparente? Sabemos que a tradução de
Proxy para nossa língua é intermediário, logo o intermediário transparente é o Proxy onde não é
necessário a configuração do navegador.
Também é possível através do Proxy transparente fazer com que todo o acesso do cliente à
Internet fique submetido ao Proxy, ou seja, o cliente é forçado a utilizar o Proxy. Entre outras
vantagens, conforme citado por Martins (2006):
• Não é necessário a configuração do navegador do cliente, isto sem dúvida é bem vindo
em uma grande rede;
• Como já dito anteriormente, o uso do Proxy transparente força o cliente a passar pelo
Proxy;
• Com a configuração do Proxy transparente, todos os serviços ficam disponíveis aos
seus clientes, lembrando que o Squid só trabalha com os protocolos HTTP e FTP.
Configurado o Proxy transparente, você pode fazer uso de outros serviços como: SSH,
Telnet, E-mail, etc;
• Outro recurso do Proxy transparente é que ele funciona como uma maneira de
bloquear acesso evitando que aqueles usuários mais espertos retirem as definições do
Proxy de dentro do navegador, podendo assim visitar sites proibidos;
Com o Proxy transparente todas as requisições feitas á porta 80 são automática
redirecionadas para a porta do Squid, e assim fica virtualmente impossível de sair para a Internet.
2.4.2 - Desvantagens do Proxy Transparente
Possui menos recursos que um Proxy Controlado. Precisa de configurações no Kernel e, em
alguns casos, é necessária a recompilação do Kernel do sistema. Não possui nenhuma segurança de
acesso e não possui um sistema de (caching), o que o torna mais lento em uma rede.
2.4.3 - Vantagens do Proxy Controlado
Com ele você pode utilizar listas de controles de acesso (ACL's) para controlar quem usa e
quem não usa o seu Proxy, pode ser utilizado para uso com SSL, pode servir para liberação de
Internet mediante autenticação do usuário e, principalmente, possui um sistema de (caching),
possuindo um desempenho na rede geralmente melhor, conforme Lima.
2.4.4 - Desvantagens do Proxy Controlado
Alguns programas como ICQ e o protocolo SMTP não funcionam muito bem com ele. E
outra particularidade é a sua falta de segurança quanto à estabilidade da conexão, pois qualquer
usuário das maquinas clientes podem remover as configurações de Proxy, no entanto não será
possível a sua navegação.
2.5 - Arquitetura do Proxy
2.5.1 - Cache
Conforme descrito por Thoeny (2002) o Proxy permite armazenar nele próprio as páginas
visitadas com mais freqüência, ou seja, quando um usuário solicita um site na Internet, o Proxy
armazena o seu conteúdo em cache, juntamente com a sua data. Caso o usuário, depois de um certo
tempo, solicite-a novamente, o Proxy obtém a data da página remota e caso não seja mais atual que
a página que está em cache, este fornece para o cliente a página em cache, sem a necessidade de
baixar novamente a página solicitada. Esta funcionalidade aumenta bastante o desempenho de
acesso às páginas, uma vez que o acesso em cache local é muito mais rápido que o acesso remoto.
2.5.2 - Autenticação
Ao requisitar uma página será exibido uma caixa solicitando ao usuário um login e uma
senha, e com base nesta autenticação de regras estabelecidas pelas ACL o usuário poderá ter ou não
acesso a página requisitada.
2.5.3 - Listas de controles de acesso
Também conhecidas como ACL's, permite que o administrador restrinja o acesso a
determinados sites baseados em critérios estipulados em listas de controles. Os critérios conforme
descrito por Thoeny (2002) podem ser expressos em regras baseadas no login, palavras-chave na
URL, palavras-chave no conteúdo do site, horário de acesso, etc.
2.5.4 - Proxy para SSL
Permite que um navegador e um servidor Web estabeleça uma comunicação segura para
realizar transações. O SSL é uma camada de criptografia do protocolo HTTP, por isto quando
utilizados em conjunto é chamado também de HTTPS (HTTP seguro).
Capitulo 3 - Squid
O Squid caracteriza-se em um software especializado, que faz operação de Proxy de Web e
FTP, completamente livre e com excelente suporte para operação em servidores Linux.
Com o Squid você pode instalar um servidor Linux com acesso à Internet, e fazer com que
outras máquinas clientes (usando sistemas operacionais como: Linux, Windows ou outros) acessem
páginas Web e sites FTP através do servidor Linux, as máquinas clientes precisam somente estar
com os seus (gateway) padrões apontados para o servidor Proxy.
O Squid dá acesso a serviços como HTTP, HTTPS e FTP. Mesmo em redes onde seria
possível instalar IP (masquerading), muitos administradores optam por limitar o acesso direto das
máquinas internas à Web, por várias razões, entre as quais se incluem a segurança e o controle de
acesso (através de mecanismos de restrição e de Log).
O recurso que mais atrai atenção no Squid é o cache de páginas. Como em geral o Link entre
as máquinas clientes e o servidor Proxy é de alta velocidade (rede local ethernet ou similar) e o link
entre o Proxy e a Web é mais lento, é bastante interessante à possibilidade que o Squid oferece de
armazenar localmente as últimas páginas acessadas, de forma a não ter que buscar novamente na
Internet uma página que tenha sido recentemente vista por outro usuário da mesma rede.
Naturalmente você pode configurar o tempo de armazenamento de cada página no cache, e o
protocolo HTTP tém recursos suficientes para reconhecer páginas que não devem ser guardadas no
cache e precisam ser buscadas novamente a cada requisição.
Devemos entender que um serviço de Proxy exige bastante memória e espaço em disco
rígido. O sistema deve ser dimensionado de forma adequada.
3.1 - Características do Proxy Squid
O Controle de acesso é uma das característica do Squid muito útil para administradores que
lidam diariamente com grandes acessos públicos, que possuem o seu link Internet saturado com
acessos a sites remotos que não estão relacionados à finalidade da sua rede e a possibilidade de
definir listas de bloqueios para restrições destes acessos indevidos.
3.1.1 - Restrições de acesso
Você pode definir listas de controle de acesso baseado no endereço de destino ou na origem
da requisição. Assim, você pode por exemplo definir que em uma escola alunos do laboratório (A)
não podem acessar determinados sites, enquanto que os alunos do laboratório (B) acessam sem
restrições. Utilizando um script externo de filtragem você pode até mesmo criar regras baseadas no
horário de acesso. Desse jeito pode-se criar restrições específicas em determinadas horas, na qual se
pode bloquear arquivos de vídeo e em outra tabela de horário pode-se permitir.
Por exemplo, as seguintes linhas no arquivo (/etc/squid.conf) impediriam que qualquer
pessoa da sua rede acesse sites, cuja URL contenha a palavra playboy e sexo: Tabela 1.
acl porno url_regex playboy
acl livre url_regex sexta
http_access deny porno
http_access allow livre
http_access allow all
Tabela 1 - Exemplo de uma acl (Reis, 2006).
Ao contrário de outras técnicas de conexão, como o roteamento simples e o IP
(masquerading), normalmente o Proxy Squid exige alterações na configuração do seu navegador
Web. Cada navegador tem sua própria maneira de configurar conforme citado por Campos(2006),
mas de um modo geral todos eles têm suporte a Proxy.
Ao configurar um navegador ou um aplicativo que estará utilizando um Proxy para estar
conectando a Internet, automaticamente ele muda a sua forma de operação. Ao invés de tentar
contatar diretamente os servidores Web da Internet, ele contata o Proxy e informa a ele a URL que
deseja transferir. O Proxy, por sua vez, contata o site da Internet e transfere o arquivo ou página
desejados, entregando-os ao navegador que fez a requisição e armazenando uma cópia temporária
no Cache. De acordo com Campos(2006), caso algum outro computador da rede requisite a mesma
página em um intervalo de tempo configurável, ele terá a resposta mais rápida.
Se você tiver um Proxy baseado no Squid, os computadores da rede local não precisam ter
nenhuma forma de acesso direto à Internet para entrar na Web e usar o FTP. Sendo assim, você pode
concentrar seus esforços de segurança e administração de rede na máquina que roda a Proxy,
conforme Campos(2006).
Uma das maiores vantagens do Proxy sobre outras alternativas de conexão como o IP
(masquerading) é a existência do cache, que, quando bem configurado, maximiza o aproveitamento
do seu canal de conexão com a Internet. Os documentos estáticos (imagens, páginas HTML
geradas estaticamente) solicitados por qualquer uma das máquinas da sua rede ficam armazenados
também no servidor, e caso outra máquina da rede solicite o mesmo documento, ele é fornecido a
partir do cache, economizando assim a sua banda com o provedor de Internet, que normalmente é
de velocidade bem mais baixa do que a rede local que liga as máquinas clientes ao servidor Proxy.
Outra vantagem importante é o nível de controle oferecido. O Squid permite criar regras
avançadas de restrição de acesso, podendo definir que determinados micros terão acesso irrestrito,
outros podem acessar apenas um determinado conjunto de sites, e outros ainda podem acessar
qualquer site. É possível restringir um determinado conjunto de sites cuja URL possua uma
determinada palavra ou expressão regular. Estas regras podem variar de acordo com o horário,
permitindo a criação de regras que restrinjam o tráfego no horário de expediente, e liberem nos
horários de menor demanda.
3.1.2 - Arquivo de Configuração
A configuração do squid fica gravada em um arquivo chamado (squid.conf), geralmente no
diretório (/etc ou /etc/squid) dependendo do sistema operacional usado.
As políticas de acesso, ocupação de memória e quanto ao prazo de validade dos arquivos do
cache são funções que estão definidas dentro do (squid.conf). Contudo, basta habilitar as funções
neste arquivo.
3.1.3 - Função do Proxy Squid
O Squid depende da infra-estrutura de sua rede. Quando ele entrar em operação, as rotas e
interfaces de rede da máquina já devem estar ativadas, sejam elas sobre uma linha discada, uma
conexão através de um roteador dedicado, uma conexão sob demanda discada, rede local ou
qualquer outra suportada pelo Linux de acordo com Campos (2006).
Conforme definição de Andrade (2006), o objetivo principal de um servidor Proxy é
possibilitar que máquinas de uma rede privada possam acessar uma rede pública, como a Internet,
sem que para isto tenham uma ligação direta com esta. O servidor Proxy costuma ser instalado em
uma máquina que tenha acesso direto à Internet, sendo que as demais efetuam as solicitações
através desta. Justamente, por isto, é que este tipo de servidor é chamado de Proxy, pois é um
procurador, ou seja, o sistema é que faz solicitações em nome dos outros.
Um servidor Proxy para o protocolo HTTP, por exemplo, pode ter outras funcionalidades
implementadas. Visto que todas as solicitações de páginas efetuadas pelas máquinas da rede privada
serão feitas através dele, é muito útil armazenar localmente as páginas que foram solicitadas,
permitindo que os próximos acessos, efetuados por quaisquer máquinas da rede, possam ser
otimizados. Este conceito é chamado de (caching), na qual a página é baixada imediatamente para o
cliente a partir do servidor Proxy, evitando ter que baixá-la da Internet.
3.1.4 - Progresso do Squid
O Squid está continuadamente melhorando sua performance, conforme Bastos (2006), além
de adicionar novas características e ter uma excelente estabilidade em condições extremas.
Sua compatibilidade com várias plataformas e a imensa gama de software para analisar logs,
gerar relatórios, melhorar o desempenho e adicionar seguranças providos pela comunidade open
source, combinados com ferramentas de administração simplificada e baseadas em Web agregam
grande valor ao produto.
Podemos ainda citar a capacidade de clustering, transparent Proxy, cache de FTP e, é claro,
seu baixo custo. O sistema é totalmente aberto, possibilitando a sua otimização à nível de código
fonte, além da otimização via configuração.
3.1.5 - Tipos de protocolos
O Squid busca por comunicação TCP (Transmission Control Protocol) e
Cache Protocol) em portas específicas. O TCP é usado para comunicação entre
clientes, e o ICP para conversa entre servidores de cache. Para cada servidor
configuração do Squid precisa fornecer uma única porta sobre a qual o Squid
requisições TCP ou ICP e ouvir as respostas.
ICP (Internet
webservers e
ou cliente, a
irá enviar as
O Squid trabalha apenas com FTP, Gopher e HTTP. O Squid, não configura acesso a emails, ICQ, IRC, etc. Visto que não só é função do firewall trabalhar com o NAT (Network Address
Translation), como também não faz sentido criar caches de e-mails pessoais e mensagens do ICQ.
3.1.6 - Proxy transparente no Squid
Proxy Transparente é um recurso muito útil para evitar que os usuários removam as
configurações do Browser. Conforme Bastos (2006) os usuários serão obrigados a passar pelo
Proxy, mesmo que as máquinas não estejam configuradas para tal. Extremamente recomendado,
principalmente em casos de bloqueio de sites ou limitação de banda.
Experiências do grupo comprovam que usuários com um pouco mais de conhecimentos irão
remover a configuração de Proxy.
Algumas pessoas desejam trabalhar ao mesmo tempo com autenticação e Proxy
transparente. Isso é possível de ser feito com uma interação entre o firewall e um CGI1.
3.1.7 - Listas de Controle de Acesso
O conceito de ACL (Access Control Lists) é utilizado no squid para estar controlando o que
cada usuário acessa no navegador. A ACL é muito útil, por nos permitir trabalhar com níveis de
acesso baseados em diversas informações.
Não é incomum que em uma instalação do Squid algumas situações podem acontecer, como
exemplo poderíamos citar a diretoria que pode acessar qualquer site, a gerência que não pode
acessar determinados sites e os funcionários da fabrica que pode acessar apenas o site da empresa e
de parceiros. Graças ao uso de ACL’s e um pouco de conhecimento, podemos fazer todas essas
restrições.
Todas as configurações de usuários, grupos, horários e sites são configuradas em ACL’s. A
ordem em que as ACL’s aparecem é muito importante, pois ao ser feita uma configuração no
arquivo fonte do Squid ele respeita a regra que vem primeiro ou o arquivo de bloqueio, por isso a
Acl que bloqueia os sites deve ser a primeira.
Outra função essencial no Squid e o suporte a autenticação que para isso se usa um recurso
chamado de (ncsa_auth), que é a alternativa mais simples. Ele está disponível junto com o Squid e
pode ser implementado rapidamente. É a solução ideal para pequenas e médias instalações e redes
com arquitetura de grupo de trabalho.
1
CGI: Consiste numa importante tecnologia que permite gerar páginas dinâmicas permitindo a um navegador passar
parâmetros para um programa alojado num servidor web.
Este é um recurso bem interessante para controle pessoal de usuários, pois permite
que você crie ACL’s individuais e gere logs de qualidade bem superior.
Existem diversos métodos de autenticação, sendo interessante averiguar exatamente o que
irá precisar com base no plano de regras.
Para controlar o acesso por usuários e grupos, podemos configurar o Squid como PDC. O
(smb_auth) lê o arquivo (\netlogon\proxyauth) que por padrão e localizado no Linux, e em um dos
controladores de domínio previamente informado. Se a leitura desse arquivo retorna um (allow) ou
permitido , então o acesso é liberado. Caso contrário se for um (deny) o acesso é negado.
Crie um arquivo chamado (proxyauth) no compartilhamento NETLOGON de seu PDC (dê
preferência ao primário). Esse arquivo deve conter unicamente a palavra (allow) e dê permissão de
leitura para os grupos e usuários que deseja permitir o acesso.
O recurso de ACL externas é muito útil para um tratamento melhorado de algum recurso que
não é compreendido por ACL’s normais. Uma ACL externa pode ser escrita em qualquer linguagem.
Ela deve sempre retornar um valor de confirmação para o (stdout) caso a condição seja satisfeita, ou
retornar um erro
para o (stdout), caso ela não seja satisfeita.
Para facilitar a vida dos usuários e do administrator, conforme citado por (Reguly 2006),
podemos criar um arquivo de configuração automática que será colocado nos Browsers dos clientes.
Dessa forma todos terão seu Proxy reconfigurado dinamicamente em caso de mudanças, sem a
necessidade de intervenção em cada máquina. Esse arquivo deve ser acessível via Web e, via de
regra, chama-se (proxy.pac).
A utilização de sistemas de cache, como o Squid, tem se mostrado excelentes para aliviar
certos sintomas, reduzindo o tráfego na rede e, conseqüentemente, a latência da mesma ou seja a
perda de banda. Toda a idéia por trás de um sistema de (caching) é criar um grande banco de dados
onde os sites mais populares ou acessados recentemente sejam armazenados para futuras consultas.
Isso significa que se 10 usuários da sua rede tentarem acessar um mesmo site ao mesmo tempo,
somente uma das conexões realmente irá ser feita a esse site. Todas as outras 9 vão se aproveitar do
primeiro acesso e utilizar a página já em memória. Isso é um enorme ganho de desempenho para
seu backbone local e para o backbone do ISP1 onde o site está armazenado e também para o
servidor que hospeda o mesmo.
Com todas essas configurações habilitadas e funcionando corretamente é possível diminuir
consideravelmente o fluxo de informações na banda e controlar ao máximo o conteúdo acessado
pelos usuários.
Podemos definir um Proxy ou cache da seguinte forma:
• Velocidade de acesso: A melhor forma de verificar se o seu cache está sendo eficiente
é pela velocidade. Um sistema de cache que não agrega velocidade não está
cumprindo o seu papel;
• Disponibilidade: De nada adianta um sistema veloz disponível apenas 2 horas por
dia, ou mesmo que precise de um reboot a cada 2 semanas. Em casos de grandes
instalações, ainda é preciso ir mais a fundo, buscando uma altíssima disponibilidade,
como (Redundância de servidores, backup, eliminação de ponto único de falha);
• Transparência ou Ostensividade: São conceitos específicos e que se adaptam a cada
caso. Grandes instalações, ISP’s e empresas não preocupadas com que seus usuários
vêem ou fazem na Internet devem preferir a transparência, onde o usuário desconhece
ou não se sente afetado (exceto pelo ganho de velocidade) pela presença de um cache.
Por outro lado, empresas com uma política de segurança mais rígida, órgãos com
informações críticas, ou mesmo pais que queiram controlar o acesso de seus filhos a
alguns sites, vão preferir a ostensividade;
1
ISP: serviço de acesso à internet, agregando a ele outros serviços relacionados, tais como "e-mail", "hospedagem de
sites" ou blogs, entre outros.
•
Capacidade de trabalhar com redes heterogêneas: Ele é capaz de trabalhar com
diversos tipos de redes e não sendo necessário estar exclusivamente amarrado a de um
fabricante de Software ou de hardware, sendo assim ele se adapta a qualquer situação.
Isso é especialmente verdade quando não sabemos que tipo de plataforma iremos
utilizar em nossa instalação;
• Simplicidade: Deixando um pouco de lado o usuário e focando no administrador,
conforme citado por (Bastos 2006) é preciso ter consciência de que um sistema bom é
um sistema fácil de administrar. O mais rápido, mais disponível e mais abrangente
sistema de (caching) é totalmente inútil se somente uma pessoa no mundo souber lidar
com ele.
Cache hierárquico é a extensão lógica do conceito de (caching). Um grupo de caches podem
se beneficiar do compartilhamento de seus dados entre si de várias formas. Isso é facilmente
explicável quando pensamos em termos regionais.
Como exemplo podemos citar o de uma empresa estabelecida em um prédio, pela qual os
usuários desta empresa resolvem enviar uma requisição de acesso a um determinado site, então é
repassado esta requisição ao Proxy mais próximo, na qual baixa-se diretamente as informações sem
precisar sair para a Internet para baixá-la.
Fica fácil de visualizar que se todas as empresas interligassem localmente seus Proxies,
todas sairiam ganhando. Na realidade, essa prática entre pequenas empresas não existe. Mas quando
falamos de grandes empresas e grandes backbone, cada 1 MB economizado com (caching) é 1 MB
ganho em outros serviços.
Além de trabalhar com o conceito de árvore conforme citado por (Bastos 2006), onde existe
um cache principal e outros ligados a ele, o Squid trabalha também com um conceito parecido com
grupo de trabalho, onde todos os servidores se consultam mutuamente. Toda a comunicação entre os
caches é feita via ICP.
O ICP foi desenvolvido como parte fundamental do projeto Harvest (Pai do Squid). Seu
objetivo é prover um método rápido e eficiente de obter-se comunicação entre servidores cache. O
ICP permite que um cache pergunte a outro se ele tem uma cópia válida de um determinado objeto,
aumentando a possibilidade de encontrar aquele objeto já (cacheado). Adicionalmente, o ICP
permite que requisições trafeguem entre servidores filhos em uma estrutura de árvore.
Além do controle de cache, o ICP também gera indicações do estado da rede. O não
recebimento de uma resposta ICP normalmente indica que a rota está congestionada ou que outro
Host não está ativo. Além disso, a ordem de chegada de uma resposta ICP pode indicar quais hosts
estão com uma distância lógica menor ou com menos carga. As mensagens ICP são geralmente bem
pequenas, com cerca de 66 bytes. Em uma estrutura hierárquica, normalmente tem-se mais trocas de
mensagens ICP do que HTTP.
Roteamento por domínio e outra características de configurações do Squid pode favorecer
muito no desempenho.
A configuração seria assim Tabela2:
cache_host_domain cache 1 portalxpto.com
cache_host_domain cache 2 portalxing.com
cache_host_domain cache 3 portalling.com
cache_host_domain cache 4 !portalxing.com ! portalxpto.com !portalling.com
Tabela 2 – Exemplo de configuração (Reis, 2006).
Sendo que o cache 4 será o responsável por todos os domínios que não sejam os 3
anteriores.
3.2 - Squid como servidor
Uma situação muito útil, mas por vezes pouco explorada do Squid é a sua capacidade de
trabalhar com Proxy reverso. Isso significa que, além de armazenar objetos remotos, criando toda
uma série de vantagens já discutidas aqui, ele também pode armazenar objetos de um servidor Web
interno, aliviando seu uso e provendo maior segurança.
3.3 - Estrutura de Hardware
Especificar o hardware é uma etapa muito importante no início do projeto. O ideal é traçar
um perfil de como é e de como será em 1 ano o volume de uso desse hardware.
Ao escolher devemos sempre utilizar um hardware que permita atualizações, especialmente
em memória e armazenamento. Instalar servidores já com todos os bancos de memória usados ou no
máximo de seus recursos sempre evitar.
Pequenas instalações dispensam disco rígido do tipo SCSI1, uma opção que já fica inviável
em instalações maiores.
Conforme citação de Bastos (2006), ao utilizar RAID2, prefira o nível 0 do que outros, visto
que o mesmo é feito para desempenho.
É interessante utilizar um disco rígido separado para os dados e para os logs do Squid. Se
isso não for possível, ao menos uma partição separada é extremamente recomendada. Como
normalmente, tanto os dados quanto os logs ficam abaixo do diretório (/var), esse é o ponto de
montagem para essa partição.
O desempenho das resoluções DNS é um ponto crítico e deve ser analisado como se segue.
Em uma situação ideal, deveria existir um cache de DNS na mesma máquina ou em uma máquina
muito próxima, para diminuir ao máximo o tempo de resolução dos nomes.
Em múltiplas rotas como em instalações com o ISP pode ser vantajoso definir suas rotas
manualmente. Já em empresas médias ou grandes que utilizam links de baixo custo, como ADSL 3, o
balanceamento de carga nos links é uma ótima opção, conforme citado por Bastos (2006).
1
SCSI: A tecnologia criada para acelerar a taxa de transferência de dados entre dispositivos de um computador, desde
que tais periféricos sejam compatíveis com o padrão.
2
RAID: É um meio de se criar uma unidade virtual composta por vários discos individuais, com a finalidade de
duplicação ou balanceamento.
3
ADSL: Asymmetric Digital Subscriber Line.
3.4 - Tags
A seguir será mostrado algumas tags de configuração do Squid. Alterações bem feitas e
pensadas podem trazer um grande ganho para a performance do cache, enquanto um erro de
configuração pode impedir o Squid de trabalhar ou até mesmo remover muitas de suas
funcionalidades.
Estas configurações são feitas editando o arquivo (squid.conf), localizado por padrão no
diretório (/etc/squid/squid.conf).
• Http_port: Esta tag define qual porta ou portas do serviço do Squid estará aberta, por
padrão é definida a 3128;
• Cachê_mem: Especifica o ideal a ser usado pelo Squid de memória, levar em
consideração a quantidade de memória usada, por que ao ser setado valores
extremamente altos os outros serviços do sistema operacional serão prejudicados;
• Cache_swap_low: Este parâmetro é especificado para quando o tamanho do diretório
de Swap já estiver no mínimo, por padrão costuma-se inserir o valor de 90;
• Cache_swap_high: Esta outra tag é para especificar o tamanho do diretório de Swap
quando o mesmo já estiver no máximo, por padrão costuma-se inserir o valor de 95.
3.5 - Referências de conexão
Em conexões intermitentes o Squid pode operar em redes (dial-up) ou (demand-dial). O
modo (off-line) irá funcionar para algumas destas redes, mas está longe de ser uma solução ideal.
Infelizmente muitas das funcionalidades do modo (off-line) do Squid parecem ter desaparecido
durante o desenvolvimento da série Squid 2.x. Na versão 2.3 STABLE4, o modo (off-line) não tem
quase nenhum efeito.
Ter um cache no lado intermitente do Link pode acabar com alguns dos problemas destas
conexões, conforme Vesperman (2006), dando acesso a informação que está em cache e assim
reduzindo o uso do Link. Sem as correções do (patche), o Squid pode funcionar razoavelmente bem
em conexões (dial-on-demand), mas discar cada vez que uma consulta tem que ser resolvida pode
influenciar consideravelmente no custo.
O Squid foi projetado para conexões permanentes. Fazer o Squid funcionar em conexões
intermitentes exige alterações no modo em que o Squid trabalha com as páginas Web antigas e
pesquisas DNS antigas.
As páginas são consideradas antigas quando o seu TTL 1(time to live) tiver sido expirado.
Muitas páginas Web possuem valores de validade em seus cabeçalhos informando até quando a
página pode se considerada atualizada, e quando a mesma pode ser considerada como página antiga.
O Squid também possui informação padrão de validade, se não há dados nos cabeçalhos, o Squid
configura os seus próprios. Páginas antigas são mantidas no cache.
Se o cache ficar sem espaço, as páginas antigas são descartadas em uma ordem (mais velha
primeiro). Este algoritmo é chamado LRU2(least recently used). Outros algoritmos estão
disponíveis em versões mais atuais do Squid.
Se mesmo assim você estiver com problemas de espaço no cache a recomendação e adquirir
um novo disco rígido com bem mais espaço e mais memória.
Páginas antigas que ficam no cache são validadas quando um cliente solicita a página. O
Squid gasta uma solicitação, perguntando (Ei, esta página mudou?), e o servidor de origem irá
responder com (Sim, aqui está à nova página), ou (Não, ela ainda é boa). A página é considerada
recente novamente, seja uma nova página ou uma antiga. Este processo é chamado de solicitação
IMS, uma abreviação para (if modified since) que significa, desde a última vez que o Squid
verificou que a mesma é recente.
Pesquisas DNS também são armazenadas em cache, e possuem um TTL configurável.
Quando uma entrada cacheada de (Fully Qualified Domain Name), FQDN, ou uma entrada IP DNS
expira, ela é removida do cache.
1
TTL: Significa o número de máquinas que os pacotes podem demorar numa rede de computadores antes de serem
descartados.
2
LRU: Algoritmo Adaptativo de Substituição de Páginas.
O modo (off-line) também nunca expira informações de DNS que esteja no cache, e nunca
renova páginas antigas. Isto não é o que os usuários de (dial-up) e outros usuários com conexões
intermitentes querem. Usando a configuração não modificada do Squid, (offline_mode on) que
assinala ao Squid para nunca tentar uma validação, e (offline_mode off) que assinala uma operação
normal.
3.6 - Vantagens
O Squid está continuadamente melhorando a sua performance, além de adicionar novas
funcionalidades e ter uma excelente estabilidade em condições extremas.
Sua compatibilidade com várias plataformas e a imensa quantidade de softwares para
analisar logs, gerar relatórios, melhorar o desempenho, bem como a adicão de segurança providos
pela comunidade open source, combinados com ferramentas de administração simplificada e
baseadas em Web agregam grande valor ao produto.
Podemos ainda citar a capacidade de clustering, transparent proxy, cache de FTP e, é claro,
seu baixo custo.
Capitulo 4 - Conhecendo Algumas Soluções
4.1 - Configuração
Esta idéia surgiu da possibilidade de configurarmos o Squid de uma forma que o mesmo
atinja o seu potencial máximo.
Porém utilizando esta idéia, iremos somente redefinir configurações pré-existentes para que
estas se encaixem no objetivo proposto. Nas páginas de anexos está o Squid proposto.
4.2 - HDparm
Aumenta a taxa de transferência de dados do discos rígidos IDE com o HDparm. Como as
maiorias das distribuições Linux sempre adaptam o sistema operacional para que ele esteja
totalmente compatível, algumas vezes é deixado de lado o desempenho do hardware e é neste caso
que entra programas como o HDparm.
A taxa de transferência de dados quintuplica com o uso dos novos parâmetros, se a
compararmos com a configuração padrão. O ganho de desempenho tende a ser muito grande mas o
risco de perda de dados é diretamente proporcional a ele. A melhor proteção é fazer primeiro um
backup do sistema e somente depois realizar teste para se chegar a um valor ideal de (multcount)
que significa a quantidade de setores que ele está lendo por vez.
4.3 - Banco de Dados
Quando pensamos em uma solução para resolver o problema proposto a principio a alteração
no código fonte seria a opção mais viável, no entanto, ao pesquisarmos e nos aprofundarmos mais
no assunto descobrimos a vantagem de utilização de bancos de dados. A vantagem de utilizar o
banco de dados é que sua indexação interna é mais rápida e dinâmica, o que facilita a resposta do
Squid para com o navegador, ou seja, a capacidade de armazenar uma grande lista diretamente no
disco rígido e não em memória como acontece normalmente.
4.4 - Alteração do Código Fonte
Uma das soluções concentra a idéia de alteração do código fonte do Squid otimizando o
mesmo, esta idéia foi proviniente de um orientador. Como seria feita esta alteração?. Pesquisamos
métodos de ordenação e métodos de busca para verificar qual deste métodos seria o mais rápido em
relação ao utilizado no Squid, caso o algoritmo utilizado atualmente pelo Squid não apresentasse
uma melhor característica de perfomance, seria aplicado um (patch) com a nossa implementação ou
melhoramento da estrutura do próprio algoritmo já existente no código fonte.
4.5 - Compilação do Kernel
Uma das opções que pode ser implementada no sistema operacional Linux que se encontra
instalado o Squid, é a compilação do Kernel com somente o necessário, ou seja, com um núcleo
(kernel) mais enxuto e dedicado, se torna evidente que o mesmo ficará mais rápido pelo fato de não
estar compartilhando outros recursos.
Capitulo 5 - Aplicando a Solução Escolhida
5.1 - A Escolha
Optamos por utilizar um banco de dados para armazenar nossa (black-list) e desenvolvemos
um programa (Front-End), que faz a intermediação entre o banco de dados e o Squid. Este
programa é desenvolvido utilizando a linguagem de programação Perl, o banco de dados que
utilizamos para armazenar a nossa (black-list) é o PostgreSQL. Dentro desta escolha incluímos
como solução requerida a implementação do HDparm e compilação do kernel e por ultimo
incluímos nas listas de anexo o hardware ideal para a quantidade de usuários.
5.2 - Desenvolvendo a solução
Utilizamos a linguagem de programação Perl, para servir como (front-end) para o banco de
dados que guardará a (black-list) do Squid. A vantagem de utilizar a linguagem Perl é sua
flexibilidade para trabalhar com qualquer banco de dados como: Oracle, Postgres, Mysql, Sqlite,
etc.
Foi feito alguns testes para conexão de banco de dados utilizando linguagem de
programação C para conectar ao banco de dados Postgres, mas devido à falta de várias bibliotecas
que são necessárias para executar esta conexão acabamos pesquisando outras linguagens e
deparamos com a linguagem Perl, ela é excelente para a função de conexão com banco de dados.
A propriedade de conexão será da seguinte forma: o Proxy Squid através de um recurso
chamado (redirect_program) que é uma tag interna do software Squid, aponta para o script feito em
Perl que é nosso (front-end) e por sua vez o (front-end) faz um SELECT na lista (black-list) que está
no banco de dados.
Vantagem sugerida é que a (black-list - lista de URL’s) não será carregada na memória e sim
no banco de dados, então o Proxy Squid fará toda a consulta de URL’s diretamente em cima do
banco de dados não sobrecarregando a memória do computador.
Testamos o (front-end) feito em Perl com o banco de dados Postgres e seu funcionamento é
perfeito, foi constatado isso através de testes utilizando os seguintes parâmetros tabela 3:
1 – Inserimos dados no banco de dados;
2 – Fizemos um select dos dados armazenados;
3 – Excluímos os dados. Todo este processo é feito através de um script Perl. O Perl utiliza uma
biblioteca chamada DBI que facilita esta conexão com o banco de dados.
Tabela 3 – O passos efetuados (Reis, 2006).
5.3 - Detalhamento do processo
O primeiro passo foi criar o banco de dados e inserir no mesmo as URL’s para serem
consultadas futuramente. O banco de dados usado como dito anteriormente é o Postgres, e foi
definido com o nome de (Bdblack) para o banco, e sua tabela com o nome (sites) com a seguinte
estrutura tabela 4:
create table sites (url varchar(300), domínio varchar (300));
Tabela 4 – Como foi estruturado (Reis, 2006).
Para o nosso (front-end) que será o intermediador entre o Squid e o banco de dados criado
pela linguagem de programação Perl o nome dele é (consulta.pl).
O código fonte segue abaixo com os devidos comentários tabela 5.
1 - #!/usr/bin/perl5.8.1
2 - use DBI;
3 - my $db = DBI->connect("dbi:Pg:dbname=bdblack","postgres","123456");
4 - print ("Site: ");
5 - chomp (my $url = <STDIN>);
6 - my $query = "SELECT * FROM sites WHERE url = '$url' OR dominio =
'$url'";
7 - my $res; #Variavel para armazenar o retorno da consulta 1 ou 0
8 - $res = $db->do($query);
9 - if ($res == 1){
10 - print ("\nSite Bloqueado\n");
11 - }
12 – else {
13 - print ("\nSite Livre\n");
14 - }
15 - $db -> disconnect();
16 – exit();
Tabela 5 – O código do front-end (Reis, 2006).
Na linha um é colocado o caminho para o executável da linguagem de programação Perl. A
segunda linha chama a biblioteca DBI para fazer a conexão entre o banco de dados e a linguagem
de programação, a linha três referencia a conexão com o banco de dados, as linhas quatro e cinco
inserem dados para a busca. A linha seis faz a consulta no banco de dados, ou seja, aqui esta os
comando SQL. Na linha sete a resposta da consulta é armazenada na variável (res), logo o seu
conteúdo deve estar com 0 ou 1, 0 não encontrado ou 1 encontrado no banco de dados. A linha 8
executa a consulta e armazena o resultado em (res), em seguida da linha nove a quatorze e
demonstrado o resultado da consulta. As linhas quinze e dezesseis são responsáveis pelo
fechamento da consulta do Perl com o banco de dados.
Logo depois de efetuado a consulta o valor é encaminhado para uma rotina onde será
definido o que será feito, se é proibido o acesso a página requisitada pelo cliente (browser) ou
liberado o seu acesso. As regras de liberação ou proibição não são efetuadas pelo (front-end), está
definição é responsabilidade do Squid com as suas ACL’s. O programa citado acima será usado para
a busca no banco de dados. Quando a memória está muito cheia e carregada de aplicativos, com
uma base de dados muito extensa ela se torna muito lenta, o nosso objetivo é colocar esta mesma
base no Postgres e ao requisitar uma URL o Squid passa para o (consulta.pl) pesquisando no banco
de dados, como se trata de muitos dados a pesquisa se torna bem mais rápida do que propriamente
na memória. E foi isso que foi realizado.
5.4 - Introdução ao Perl
A Linguagem Prática de Extração e Geração de Relatórios (The Practical Extraction and
Report Language) é uma linguagem de programação estável e multiplataforma, usada em
aplicações de missão crítica em todos os setores, e é bastante usada para desenvolver aplicações
Web de todos os tipos, foi criada por Larry Wall em dezembro de 1987. A origem do Perl remonta
ao (shell scripting, Awk e à linguagem C), e está disponível para praticamente todos os sistemas
operacionais, mas é usado mais comumente em sistemas Unix e compatíveis.
Perl é uma das linguagens preferidas por administradores de sistema e autores de aplicações
para a Web. É especialmente versátil no processamento de cadeias (strings), manipulação de texto e
no (pattern matching) implementado através de expressões regulares, além de permitir tempos de
desenvolvimento curtos.
A linguagem Perl já foi portada para mais de 100 diferentes plataformas, e é bastante usada
em desenvolvimento Web, finanças e bioinformática.
5.4.1 Características do Perl
No geral, a sintaxe de um programa em Perl se parece muito com a de um programa em C,
existem variáveis, expressões, atribuições, blocos de código delimitados, estruturas de controle e
sub-rotinas.
Além disso, Perl foi bastante influenciado pelas linguagens de shell script, todas as variáveis
são precedidas por um cifrão ($). Essa marcação permite identificar perfeitamente as variáveis em
um programa, aonde quer que elas estejam. Um dos melhores exemplos da utilidade desse recurso é
a interpolação de variáveis diretamente no conteúdo de strings. Perl também possui muitas funções
integradas para tarefas comuns como ordenação e acesso de arquivos em discos rígidos.
A linguagem suporta estruturas de dados arbitrariamente complexas. Ela também possui
recursos vindos da programação funcional (as funções são vistas como um outro valor qualquer
para uma subrotina, por exemplo) e um modelo de programação orientada a objetos. Todas as
versões de Perl possuem gerenciamento de memória automático e tipamento dinâmico. Os tipos e
necessidades de cada objeto de dados no programa são determinados automaticamente. A memória
é alocada ou liberada de acordo com o necessário. A conversão entre tipos de variáveis é feita
automaticamente em tempo de execução e conversões ilegais são erros fatais.
Sua interface de integração com base de dados (DBI) suporta muitos bancos de dados,
incluindo Oracle, Sybase, PostgreSQL, MySQL e outros. Perl permite programação procedural e
orientada a objetos. Perl pode acessar bibliotecas externas em C e C++. O módulo Perl (CGI.pm),
parte da distribuição padrão de Perl, faz com que a manipulação de formulários HTML seja muito
simples.
Perl pode manipular dados encriptados, incluindo transações de comércio eletrônico.
O pacote DBI do Perl faz com que a integração com banco de dados Postgres seja muito
simples.
5.5 - Introdução ao PostgreSQL
O PostgreSQL é um sistema gerenciador de banco de dados objeto-relacional (SGBDOR1),
baseado no POSTGRES Versão 4.2 desenvolvido pelo Departamento de Ciência da Computação da
Universidade da Califórnia em Berkeley. O POSTGRES foi pioneiro em vários conceitos que
somente se tornaram disponíveis muito mais tarde em alguns sistemas de banco de dados
comerciais.
O PostgreSQL é um descendente de código fonte aberto do código original de Berkeley. São
suportados o SQL-92 e o SQL-1999, além de serem oferecidas muitas funcionalidades modernas,
como:
• comandos complexos ;
• chaves estrangeiras;
• gatilhos;
• visões;
• integridade transacional;
• controle de simultaneidade multiversão.
Além disso, o PostgreSQL pode ser estendido pelo usuário de muitas maneiras como, por
exemplo, adicionando novos:
• tipos de dados;
• funções;
• operadores;
• funções de agregação;
• métodos de índice;
• linguagens procedurais.
Devido à sua licença livre, o PostgreSQL pode ser utilizado, modificado e distribuído por
qualquer pessoa para qualquer finalidade, seja privada, comercial ou acadêmica, livre de encargos.
SGBDOR1: Sistema gerenciador de banco de dados objeto relacional.
5.6 - Outras soluções aplicadas
5.6.1 - O HDparm
Conforme a definição de (Thomas Wölfer 2004) o Hdparm é essencial para prover
desempenho em discos rígidos IDE em sistemas Linux recém-instalados, que não utiliza o total de
possibilidades oferecidas pelo hardware. O Hdparm consegue modificar a configuração do disco
rígido obtendo o máximo do mesmo. Através do comando (hdparm –Tt /dev/hdaX) podemos medir
a velocidade do cache do disco (memória, processador e buffer) que durante a leitura de
informações calcula os valores de desempenho do disco desconsiderando as informações de dados
do cache fornecendo uma medida eficiente do disco rígido que está sendo analisado. É
recomendável efetuar vários testes, a fim de calcular uma média, entretanto é necessário que
desabilitemos vários serviços no computador para que o mesmo não fique sobrecarregado durante
os testes prejudicando a precisão dos dados analisados.
Aplicando o HDparm de forma criteriosa podemos aumentar em até cinco vezes o
desempenho do disco rígido, algo ideal para aplicações que necessitem de respostas altas. Algumas
controladoras suportam 32 bits e estão rodando em 16 bits, este suporte pode ser configurado com a
opção (–c), conforme segue (hdparm –c1 –mf6 /dev/hdaX), com este comando o suporte a (I/0) é
configurado para o modo 1 que seria 32 bits, desta forma dobramos a taxa de transferência de
dados do disco rígido. Aplicando o comando (Hdparm –d1 –x66-u1 –m16 –cd /dev/hdaX), obtemos
resultados que demonstram grande desempenho do disco rígido, através da opção (–d1) ativamos o
(flag) de utilização de acesso direto à memória (using-dma), a opção (–x66) ativa o ULTRADMA, a
opção (–u1) desativa o mascaramento de outras interrupções (umaskirq). Podemos observar que a
taxa de transferência de dados quintuplica com o uso de novos parâmetros comparado a
configuração padrão do computador.
Depois de efetuar a configuração que aplica o desempenho do disco rígido através do
HDparm devemos salvar a mesma para que a configuração não perca durante a reinicialização do
sistema, basta utilizar um script de inicialização do sistema, chamado (rc.local) ou outro nome
dependendo da distribuição para que toda a configuração fique de forma permanente, mas talvez
em algumas controladoras, é realizado um parâmetro chamado (IDE reset) pode-se ainda perder a
configuração. Aplicando a opção (–k1) no comando evitamos que tal reset seja efetuado. A seguir
apresentamos uma tabela feita com 3 discos rígidos, demonstramos os dados que possuem valores
surpreendente tabela 6.
Disco Rígido
ST3400I5A
SAMSUNG
SV2001.4
Performance
Veloc. Gravação
Sem HDparm
Cached reads -2.00 368.00 MBps
seg
Buffered disk reads 52,1 MBps
– 3.01seg
Cached reads -2.00 680.35 MBps
seg
Buffered disk reads 28.63 MBps
– 3.01 seg
Tabela 6 – Valores encontrados (Reis, 2006).
Com HDparm
378,11 MBps
36,54 MBps
686.9 MBps
24.77 MBps
5.6.2 – Kernel1
Para ganhar uma alta performance no sistema operacional Linux o ideal e compilar o Kernel
(núcleo do sistema operacional, que faz a negociação entre Hardware e Software), com um kernel
compilado somente com o básico, ou seja, com suporte no kernel somente aos hardware que estão
disponíveis na máquina, a velocidade em processamento é aproveitada somente para as aplicações
em uso, à memória fica alocada somente para os aplicativos e serviços que o sistema operacional
precisa.
Os procedimento abaixo foi citado por Gustavo Paes (2004), o foco é o kernel 2.6 com
Linux Slackware 9, porém seus conceitos podem ser levados para outras distribuições. Antes de
tudo, atualize o (Modutils/module-init-tools). É necessario um conjunto novo de programas de
gerenciamento de módulos (modprobe, insmod, rmmod, etc), pois os que vêm com o Slackware 9
não funcionam para o kernel 2.6.2 (Figura 1).
1 - Baixe o module-init-tools mais recente:
ftp://ftp.kernel.org/pub/linux/kernel/people/rusty/modules/
2. Descompacte o arquivo com:
$ tar -xvzf module-init-tools-0.9.15-pre4.tar.gz
3. Entre no diretório que foi criado:
$ cd module-init-tools-0.9.15-pre4
4. Leia o arquivo README se houver a necessidade.
5. Agora é a hora de compilar:
$ ./configure --prefix=/
$ make moveold
$ make
$ su
# make install
6.Usar programa (generate-modprobe.conf) e converta o /etc/modules.conf para
/etc/modprobe.conf:
# ./generate-modprobe.conf /etc/modprobe.conf
Kernel1: É entendido como o núcleo do Sistema Operacional ou, numa tradução literal, cerne.
NOTA: Os procedimentos a seguir devem ser executados pelo usuário root.
1. Baixe o kernel novo em:
http://www.kernel.org/pub/linux/kernel/v2.6/linux-2.6.2.tar.bz2
2. Descompacte-o na pasta /usr/src/:
# cd /usr/src
# tar -xvjf linux-2.6.2.tar.bz2
3. Recrie o link simbólico "linux" apontando para a pasta do novo kernel:
# ln -s /usr/src/linux-2.6.2 linux
4. Entre no diretório /usr/src/linux:
# cd /usr/scr/linux
5. Resete as configurações do kernel:
# make mrproper
6. Configure os módulos do seu kernel:
# make xconfig
Existem duas formas de carregar os dispositivos no kernel, como módulo (tecla M) e como
parte do kernel (tecla Y).
Opte por carregar como módulo, isto acelera a velocidade, isso necessita usar o
(/etc/rc.d/rc.local) descrito acima ou o (/etc/modprobe.conf) para carregar os módulos
automaticamente.
Em LOADABLE MODULE SUPPORT, habilite o carregamento automático de módulos, ele
vai tentar carregar as dependências de um módulo que você esteja tentando carregar;
Em PROCESSOR TYPE, escolha o processador, um kernel específico para o processador é
bem mais rápido e estável que um de 486.
Nessa ponto, tenha em mãos o manual da placa mãe, placa de vídeo, placa de TV, modem,
etc;
Em NETWORK SUPPORT, habilite os drivers da placa de rede.
Não use o (i2c) como parte do kernel, isso da futuros problemas na compilação do kernel.
Em SOUND, desabilite a placa de som, recomendamos também que na BIOS seja
desabilitado Usb, Sound, Porta paralela.
Lembre-se na parte de sistemas de arquivos habilitar suporte ao EXT2, EXT3 e ReiserFS.
Em CARACTER DEVICES, coloque os drivers para AGP. Recomendação é de usar estes
drivers como parte do kernel.
Em ATA/ATAPI/M, habilite a emulação de SCSI, pois a maioria dos softwares de gravação
para o GNU/Linux requerem que a gravadora esteja no modo SCSI.
Em GRAPHIC SUPPORT, ative o suporte a frame buffer. Ainda em frame buffer, ative o
VGA 16-Color e o VESA VGA, estes dois como parte do kernel;
Ative o driver de sua placa de vídeo como módulo (SIS, NVIDIA, ATI, etc), senão ficará
difícil de atualizar depois, principalmente no caso da NVIDIA.
Em CONSOLE DISPLAY DRIVER SUPPORT, ative o VGA TEXT CONSOLE e o VIDEO
MODE SELECTION SUPPORT.
Ative o FRAMEBUFFER CONSOLE SUPPORT, selecione também SELECT COMPILEDIN FONTE e marque as fontes 8x8, 8x16 e 4x6.
Ative em LOGO CONFIGURATION todas as opções.
7. Limpe os arquivos temporários e de instalação:
# make clean
8. Compile a imagem do kernel:
# make bzImage
9. Compile os módulos do kernel (isso mesmo só um make):
# make
10. Instale os módulos do kernel:
# make modules_install
11. Copie a imagem gerada para o /boot/:
# cp /usr/src/linux-2.6.2/arch/i386/boot/bzImage /boot/linux-2.6.2
12. Edite o /etc/lilo.conf:
# vi /etc/lilo.conf
e inclua as seguintes linhas no arquivo:
image=/boot/linux-2.6.2
label=Linux-2.6.2
read-only
13. Atualize o boot do sistema:
# lilo
Figura 1 – Exemplo de configuração do Kernel (Reis, 2006).
Capítulo 6 - Conclusão
Durante a pesquisa encontramos algumas aplicações, conforme descrição anterior que foram
implementadas, a fim de aperfeiçoar o desempenho do Squid.
No entanto a nossa aplicação principal foi com o banco de dados PostgreSQL, na qual
demonstrou que a sua implementação com o Squid pode ser uma boa alternativa, tanto em
desempenho quanto na economia de hardware. Nas pesquisas foram encontradas somente uma
pessoa (Alvaro Mendes de Oliveira (2006) - Squid Plus com AD, redirector, controle de banda e
relatórios) que implementou este método com o banco de dados Mysql. Nossos
testes
demonstraram que com um hardware especifico, compilando o kernel somente com o mínimo e
não compartilhando serviços, adicionando o recurso de HDparm corretamente ao disco rígido, e
com a implementação do uso do banco de dados o aumento na velocidade de transferência e
resposta do Squid é aumentada.
O programa fez a busca no banco de dados e retornou ao Squid com maior velocidade, isto
é, deixou-se de utilizar consideravelmente a memória física do equipamento (RAM) e passou-se a
utilizar o disco rígido (HD) utilizando para isto softwares como o Postgres para responder as
requisições com muito mais velocidade.
Com tudo isto que apresentamos neste trabalho, podemos concluir que ao utilizar estas
ferramentas em conjunto (Front-end, HDparm, compilação de Kernel), podemos melhorar a
performance do Squid sem alterar a estrutura do hardware. Assim sendo, com idéias simples
economizamos um investimento em hardware que era o nosso objetivo inicial.
Lista de anexos
Scripts utilizados para o front-end com Mysql
Ligação à Bases de Dados:
#!/usr/bin/perl
use
DBI;
#módulo
para
acesso
a
bases
de
dados
$database="test";
#identificador
da
base
de
dados
$username="g2c";
#utilizador
da
base
de
dados
$password="teste";
#password
do
utilizador
da
base
de
dados
$host="locahost";
#hostname
da
base
de
dados
print
"Content-type:
text/plain\n\n";
print
"A
testar
ligacao
a
BD\n\n";
#
estabelecer
a
ligacao
my
$dbh
=
DBI->connect(
"DBI:mysql:database=$database;host=$host",
$username,$password);
if
($dbh)
{
print
"Ligado!\n";
}
else
{
print
"Erro
na
Ligacao!:
$?,
$!,
$dbh\n";
}
if
($dbh)
{
$dbh->disconnect;
}
exit(0);
Criação de uma Tabela:
#!/usr/bin/perl
use DBI;
$database="test";
$username="g2c";
$password="teste";
$host="localhost";
print "Content-type: text/plain\n\n";
print "\n";
my $dbh=DBI->connect( "DBI:mysql:database=$database;host=$host",
$username,$password);
if ($dbh) {
print "Ligado!\n";
} else {
print "Falha na Ligacao: $?, $!, $dbh\n";
}
$dbh->do( "CREATE TABLE squid (id INT NOT NULL AUTO_INCREMENT, " .
"url VARCHAR (200), PRIMARY KEY(id))") or print "Falha na criacao da tabela\n";
if ($dbh) {
$dbh->disconnect;
}
exit(0);
Remover uma Tabela:
#!/usr/bin/perl
use
DBI;
$database="test";
$username="g2c";
$password="teste";
$host="localhost";
print
"Content-type:
text/plain\n\n";
print
"\n";
my
$dbh=DBI->connect("DBI:mysql:database=$database;host=$host",
$username,$password);
if
($dbh)
{
print
"connected\n";
}
else
{
print
"not
connected:
$?,
$!,
$dbh\n";
}
$dbh->do("DROP TABLE squid") or print "Falha na eliminacao da tabela\n";
if
($dbh)
{
$dbh->disconnect;
}
exit(0);
Acesso aos Dados de uma Tabela:
#!/usr/bin/perl
use DBI;
$database="test";
$username="g2c";
$password="teste";
$host="localhost";
print "Content-type: text/html\n\n";
print "\n";
my $dbh=DBI->connect("DBI:mysql:database=$database;host=$host",
$username,$password);
if ($dbh) {
print "Ligado!\n";
} else {
print "Erro na Ligacao!: $?, $!, $dbh\n";
}
my $sth=$dbh->prepare("SELECT * FROM squid");
$sth->execute();
while(my $ref = $sth->fetchrow_hashref())
{
print "<tr><td>$ref->{'url'}</td></tr>\n";
}
print "</table>\n";
if ($dbh) {
$dbh->disconnect;
}
exit(0);
Criação de um Registo numa Tabela:
#!/usr/bin/perl
use DBI;
$database="test";
$username="g2c";
$password="teste";
$host="localhost";
print "Content-type: text/plain\n\n";
print "\n";
my $dbh=DBI->connect("DBI:mysql:database=$database;host=$host",
$username,$password);
if ($dbh) {
print "Ligado!\n";
} else {
print "Falha na Ligação: $?, $!, $dbh\n";
}
$dbh->do("INSERT INTO squid VALUES('4', 'www.sex.com'
)") or print "Falha na insercao\n";
if ($dbh) {
$dbh->disconnect;
}
exit(0);
Comandos usados na criação das tabelas.
############Copiando os dados para a tabela######################
copy squid from '/home/squid/squid.txt' delimiter as ',';
################################################################
#########Criando a tabela direto no banco bdblack################
psql -f tabelasites bdblack
#################################################################
cat urls | awk -F "/" '{print$1"/"$2","$2}'
Hardware Recomendado Para Quantidade de Usuarios
Configuracao Ideal *
Quantidade de Usuarios Hardware Recomendado
MotherBoard
Memoria
Processador
Ate 50 **
HD IDE/SATA
Placa de Rede
Configuracoes
Intel ou Via
1 Gb
Intel Celeron D 2.8 Ghz
40 Gb
Intel ou Realtek
Quantidade
1
1
1
1
2 a3
Quantidade de Usuarios Hardware Recomendado
MotherBoard
Memoria
Processador
Ate 100
HD IDE/SATA
Placa de Rede
Configuracoes
Intel ou Via
1 Gb
Intel Pentium 4 HT 3 Ghz
80 Gb
Intel ou Realtek
Quantidade
1
1
1
1
3
Quantidade de Usuarios Hardware Recomendado
MotherBoard
Memoria
Processador
Ate 500
HD IDE/SATA/SCSI
Placa de Rede
Configuracoes
Intel ou Via
2 Gb
Intel Pentium 4 HT 3.4 Ghz
120 Gb
Intel ou Realtek
Quantidade
1
2
1
1
3
Quantidade de Usuarios Hardware Recomendado
MotherBoard
Memoria
Processador
Ate 1000
HD IDE/SATA/SCSI
Placa de Rede
Configuracoes
Intel com Chipset Intel
3 Gb
Intel Pentium 4 HT 3.4 Ghz
80 Gb
Intel ou Realtek
Quantidade
1
3
2
2
3
Quantidade de Usuarios Hardware Recomendado Configuracoes
MotherBoard
Intel Xeon com Chipset Intel
Memoria
4 Gb
Processador
Intel Xeon 3.4 Ghz
Acima de 1000
HD /SATA/SCSI
120 Gb
Placa de Rede
Intel ou Realtek
Obs: Jamais utilizar a motherbord com Chipset SIS
*Considerando padroes que nao sejam altos de e-mail e pager view
**Para 50 usuários /contas de e-mail:
Celeron D 2.53Ghz com 1Gb de RAM, CDROM, HD de 40Gb, 2 placas de rede.
(*) Com base no cenário abaixo
-50 usuarios logados simultâneos link de 1Mbit
-24 Mbytes de tráfego de e-mails (Antivirus e AntiSpam)
-72 hits hora no Webmail
-840 Acesso hora POP
Quantidade
1
3
2
2
3
squid.conf
http_port 3128
hierarchy_stoplist cgi-bin ?
acl QUERY urlpath_regex cgi-bin \?
no_cache deny QUERY
cache_mem 32 MB
cache_swap_low 90
cache_swap_high 95
maximum_object_size 4098 KB
minimum_object_size 0 KB
maximum_object_size_in_memory 8 KB
redirect_program /home/squid/consulta.pl
cache_dir ufs /var/lib/squid/cache 100 16 256
cache_access_log /var/lib/squid/logs/access.log
cache_log /var/lib/squid/logs/cache.log
cache_store_log /var/lib/squid/logs/store.log
pid_filename /var/lib/squid/logs/squid.pid
client_netmask 255.255.255.0
dns_retransmit_interval 5 seconds
dns_timeout 2 minutes
dns_nameservers 192.168.170.1
refresh_pattern ^ftp: 1440 20% 10080
refresh_pattern ^gopher: 1440 0% 1440
refresh_pattern . 0 20% 4320
acl all src 0.0.0.0/0.0.0.0
acl manager proto cache_object
acl localhost src 127.0.0.1/255.255.255.255
acl to_localhost dst 127.0.0.0/8
acl SSL_ports port 443 563
acl Safe_ports port 80 # http
acl Safe_ports port 21 # ftp
acl Safe_ports port 443 563 # https, snews
acl Safe_ports port 70 # gopher
acl Safe_ports port 210 # wais
acl Safe_ports port 1025-65535 # unregistered ports
acl Safe_ports port 280 # http-mgmt
acl Safe_ports port 488 # gss-http
acl Safe_ports port 591 # filemaker
acl Safe_ports port 777 # multiling http
acl CONNECT method CONNECT
#Recommended minimum configuration:
#
# Only allow cachemgr access from localhost
http_access allow manager localhost
http_access deny manager
# Deny requests to unknown ports
http_access deny !Safe_ports
# Deny CONNECT to other than SSL ports
http_access deny CONNECT !SSL_ports
emulate_httpd_log on
## Autenticacao #################################################
auth_param basic program /usr/libexec/ncsa_auth /etc/squid/passwd
auth_param basic children 5
auth_param basic realm Entre com o USUARIO E SENHA!
auth_param basic casesensitive off
##bloqueia por url############################
acl gruporestrito proxy_auth "/etc/squid/grprestrito"
acl gruposacesso proxy_auth "/etc/squid/grpacessototal"
acl bloqueios_url url_regex "/etc/squid/siteproibido"
acl formato_proibe urlpath_regex "/etc/squid/formatosproibidos"
## Listas de acesso ###########################
acl autenticacao proxy_auth REQUIRED
http_access allow gruposacesso
http_access deny bloqueios_url
http_access deny formato_proibe
http_access allow gruporestrito
http_reply_access allow all
acl our_networks src 192.168.170.0/24
http_access allow our_networks
icp_access allow all
cache_mgr [email protected]
visible_hostname spekitru.servidor.com.br
error_directory /usr/share/squid/errors/Portuguese
http_access deny all
/*
* $Id: acl.c,v 1.270.2.29 2004/09/25 11:56:16 hno Exp $
*
* DEBUG: section 28
Access Control
* AUTHOR: Duane Wessels
*
* SQUID Web Proxy Cache
http://www.squid-cache.org/
* ---------------------------------------------------------*
* Squid is the result of efforts by numerous individuals from
* the Internet community; see the CONTRIBUTORS file for full
* details. Many organizations have provided support for Squid's
* development; see the SPONSORS file for full details. Squid is
* Copyrighted (C) 2001 by the Regents of the University of
* California; see the COPYRIGHT file for full details. Squid
* incorporates software developed and/or copyrighted by other
* sources; see the CREDITS file for full details.
*
* 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., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
*
*/
#include "squid.h"
#include "splay.h"
static void aclParseDomainList(void *curlist);
static void aclParseUserList(void **current);
static void aclParseIpList(void *curlist);
static void aclParseIntlist(void *curlist);
#if SQUID_SNMP
static void aclParseWordList(void *curlist);
#endif
static void aclParseProtoList(void *curlist);
static void aclParseMethodList(void *curlist);
static void aclParseTimeSpec(void *curlist);
static void aclParseIntRange(void *curlist);
static void aclDestroyTimeList(acl_time_data * data);
static void aclDestroyIntRange(intrange *);
static void aclLookupProxyAuthStart(aclCheck_t * checklist);
static void aclLookupProxyAuthDone(void *data, char *result);
static struct _acl *aclFindByName(const char *name);
static int aclMatchAcl(struct _acl *, aclCheck_t *);
static int aclMatchTime(acl_time_data * data, time_t when);
static int aclMatchUser(void *proxyauth_acl, char *user);
static int aclMatchIp(void *dataptr, struct in_addr c);
static int aclMatchDomainList(void *dataptr, const char *);
static int aclMatchIntegerRange(intrange * data, int i);
#if SQUID_SNMP
static int aclMatchWordList(wordlist *, const char *);
#endif
static void aclParseUserMaxIP(void *data);
static void aclDestroyUserMaxIP(void *data);
static wordlist *aclDumpUserMaxIP(void *data);
static int aclMatchUserMaxIP(void *, auth_user_request_t *, struct in_addr);
static void aclParseHeader(void *data);
static void aclDestroyHeader(void *data);
static squid_acl aclStrToType(const char *s);
static int decode_addr(const char *, struct in_addr *, struct in_addr *);
static void aclCheck(aclCheck_t * checklist);
static void aclCheckCallback(aclCheck_t * checklist, allow_t answer);
#if USE_IDENT
static IDCB aclLookupIdentDone;
#endif
static IPH aclLookupDstIPDone;
static IPH aclLookupDstIPforASNDone;
static FQDNH aclLookupSrcFQDNDone;
static FQDNH aclLookupDstFQDNDone;
static EAH aclLookupExternalDone;
static wordlist *aclDumpIpList(void *);
static wordlist *aclDumpDomainList(void *data);
static wordlist *aclDumpTimeSpecList(acl_time_data *);
static wordlist *aclDumpRegexList(relist * data);
static wordlist *aclDumpIntlistList(intlist * data);
static wordlist *aclDumpIntRangeList(intrange * data);
static wordlist *aclDumpProtoList(intlist * data);
static wordlist *aclDumpMethodList(intlist * data);
static SPLAYCMP aclIpAddrNetworkCompare;
static SPLAYCMP aclIpNetworkCompare;
static SPLAYCMP aclHostDomainCompare;
static SPLAYCMP aclDomainCompare;
static SPLAYWALKEE aclDumpIpListWalkee;
static SPLAYWALKEE aclDumpDomainListWalkee;
static SPLAYFREE aclFreeIpData;
#if USE_ARP_ACL
static void aclParseArpList(void *curlist);
static int decode_eth(const char *asc, char *eth);
static int aclMatchArp(void *dataptr, struct in_addr c);
static wordlist *aclDumpArpList(void *);
static SPLAYCMP aclArpCompare;
static SPLAYWALKEE aclDumpArpListWalkee;
#endif
static int aclCacheMatchAcl(dlink_list * cache, squid_acl acltype, void *data, char
*MatchParam);
static squid_acl
aclStrToType(const char *s)
{
if (!strcmp(s, "src"))
return ACL_SRC_IP;
if (!strcmp(s, "dst"))
return ACL_DST_IP;
if (!strcmp(s, "myip"))
return ACL_MY_IP;
if (!strcmp(s, "domain"))
return ACL_DST_DOMAIN;
if (!strcmp(s, "dstdomain"))
return ACL_DST_DOMAIN;
if (!strcmp(s, "srcdomain"))
return ACL_SRC_DOMAIN;
if (!strcmp(s, "dstdom_regex"))
return ACL_DST_DOM_REGEX;
if (!strcmp(s, "srcdom_regex"))
return ACL_SRC_DOM_REGEX;
if (!strcmp(s, "time"))
return ACL_TIME;
if (!strcmp(s, "pattern"))
return ACL_URLPATH_REGEX;
if (!strcmp(s, "urlpath_regex"))
return ACL_URLPATH_REGEX;
if (!strcmp(s, "url_regex"))
return ACL_URL_REGEX;
if (!strcmp(s, "port"))
return ACL_URL_PORT;
if (!strcmp(s, "myport"))
return ACL_MY_PORT;
if (!strcmp(s, "maxconn"))
return ACL_MAXCONN;
#if USE_IDENT
if (!strcmp(s, "ident"))
return ACL_IDENT;
if (!strcmp(s, "ident_regex"))
return ACL_IDENT_REGEX;
#endif
if (!strncmp(s, "proto", 5))
return ACL_PROTO;
if (!strcmp(s, "method"))
return ACL_METHOD;
if (!strcmp(s, "browser"))
return ACL_BROWSER;
if (!strcmp(s, "referer_regex"))
return ACL_REFERER_REGEX;
if (!strcmp(s, "proxy_auth"))
return ACL_PROXY_AUTH;
if (!strcmp(s, "proxy_auth_regex"))
return ACL_PROXY_AUTH_REGEX;
if (!strcmp(s, "src_as"))
return ACL_SRC_ASN;
if (!strcmp(s, "dst_as"))
return ACL_DST_ASN;
#if SQUID_SNMP
if (!strcmp(s, "snmp_community"))
return ACL_SNMP_COMMUNITY;
#endif
#if SRC_RTT_NOT_YET_FINISHED
if (!strcmp(s, "src_rtt"))
return ACL_NETDB_SRC_RTT;
#endif
#if USE_ARP_ACL
if (!strcmp(s, "arp"))
return ACL_SRC_ARP;
#endif
if (!strcmp(s, "req_mime_type"))
return ACL_REQ_MIME_TYPE;
if (!strcmp(s, "rep_mime_type"))
return ACL_REP_MIME_TYPE;
if (!strcmp(s, "rep_header"))
return ACL_REP_HEADER;
if (!strcmp(s, "req_header"))
return ACL_REQ_HEADER;
if (!strcmp(s, "max_user_ip"))
return ACL_MAX_USER_IP;
if (!strcmp(s, "external"))
return ACL_EXTERNAL;
if (!strcmp(s, "urllogin"))
return ACL_URLLOGIN;
return ACL_NONE;
}
const char *
aclTypeToStr(squid_acl type)
{
if (type == ACL_SRC_IP)
return "src";
if (type == ACL_DST_IP)
return "dst";
if (type == ACL_MY_IP)
return "myip";
if (type == ACL_DST_DOMAIN)
return "dstdomain";
if (type == ACL_SRC_DOMAIN)
return "srcdomain";
if (type == ACL_DST_DOM_REGEX)
return "dstdom_regex";
if (type == ACL_SRC_DOM_REGEX)
return "srcdom_regex";
if (type == ACL_TIME)
return "time";
if (type == ACL_URLPATH_REGEX)
return "urlpath_regex";
if (type == ACL_URL_REGEX)
return "url_regex";
if (type == ACL_URL_PORT)
return "port";
if (type == ACL_MY_PORT)
return "myport";
if (type == ACL_MAXCONN)
return "maxconn";
#if USE_IDENT
if (type == ACL_IDENT)
return "ident";
if (type == ACL_IDENT_REGEX)
return "ident_regex";
#endif
if (type == ACL_PROTO)
return "proto";
if (type == ACL_METHOD)
return "method";
if (type == ACL_BROWSER)
return "browser";
if (type == ACL_REFERER_REGEX)
return "referer_regex";
if (type == ACL_PROXY_AUTH)
return "proxy_auth";
if (type == ACL_PROXY_AUTH_REGEX)
return "proxy_auth_regex";
if (type == ACL_SRC_ASN)
return "src_as";
if (type == ACL_DST_ASN)
return "dst_as";
#if SQUID_SNMP
if (type == ACL_SNMP_COMMUNITY)
return "snmp_community";
#endif
#if SRC_RTT_NOT_YET_FINISHED
if (type == ACL_NETDB_SRC_RTT)
return "src_rtt";
#endif
#if USE_ARP_ACL
if (type == ACL_SRC_ARP)
return "arp";
#endif
if (type == ACL_REQ_MIME_TYPE)
return "req_mime_type";
if (type == ACL_REP_MIME_TYPE)
return "rep_mime_type";
if (type == ACL_REP_HEADER)
return "rep_header";
if (type == ACL_REQ_HEADER)
return "req_header";
if (type == ACL_MAX_USER_IP)
return "max_user_ip";
if (type == ACL_EXTERNAL)
return "external";
if (type == ACL_URLLOGIN)
return "urllogin";
return "ERROR";
}
static acl *
aclFindByName(const char *name)
{
acl *a;
for (a = Config.aclList; a; a = a->next)
if (!strcasecmp(a->name, name))
return a;
return NULL;
}
static void
aclParseIntlist(void *curlist)
{
intlist **Tail;
intlist *q = NULL;
char *t = NULL;
for (Tail = curlist; *Tail; Tail = &((*Tail)->next));
while ((t = strtokFile())) {
q = memAllocate(MEM_INTLIST);
q->i = atoi(t);
*(Tail) = q;
Tail = &q->next;
}
}
static void
aclParseIntRange(void *curlist)
{
intrange **Tail;
intrange *q = NULL;
char *t = NULL;
for (Tail = curlist; *Tail; Tail = &((*Tail)->next));
while ((t = strtokFile())) {
q = xcalloc(1, sizeof(intrange));
q->i = atoi(t);
t = strchr(t, '-');
if (t && *(++t))
q->j = atoi(t);
else
q->j = q->i;
*(Tail) = q;
Tail = &q->next;
}
}
static void
aclParseProtoList(void *curlist)
{
intlist **Tail;
intlist *q = NULL;
char *t = NULL;
protocol_t protocol;
for (Tail = curlist; *Tail; Tail = &((*Tail)->next));
while ((t = strtokFile())) {
protocol = urlParseProtocol(t);
q = memAllocate(MEM_INTLIST);
q->i = (int) protocol;
*(Tail) = q;
Tail = &q->next;
}
}
static void
aclParseMethodList(void *curlist)
{
intlist **Tail;
intlist *q = NULL;
char *t = NULL;
for (Tail = curlist; *Tail; Tail = &((*Tail)->next));
while ((t = strtokFile())) {
q = memAllocate(MEM_INTLIST);
q->i = (int) urlParseMethod(t);
*(Tail) = q;
Tail = &q->next;
}
}
/*
* Decode a ascii representation (asc) of a IP adress, and place
* adress and netmask information in addr and mask.
* This function should NOT be called if 'asc' is a hostname!
*/
static int
decode_addr(const char *asc, struct in_addr *addr, struct in_addr *mask)
{
u_num32 a;
int a1 = 0, a2 = 0, a3 = 0, a4 = 0;
switch (sscanf(asc, "%d.%d.%d.%d", &a1, &a2, &a3, &a4)) {
case 4:
/* a dotted quad */
if (!safe_inet_addr(asc, addr)) {
debug(28, 0) ("decode_addr: unsafe IP address: '%s'\n", asc);
fatal("decode_addr: unsafe IP address");
}
break;
case 1:
/* a significant bits value for a mask */
if (a1 >= 0 && a1 < 33) {
addr->s_addr = a1 ? htonl(0xfffffffful << (32 - a1)) : 0;
break;
}
default:
debug(28, 0) ("decode_addr: Invalid IP address '%s'\n", asc);
return 0;
/* This is not valid address */
}
if (mask != NULL) {
/* mask == NULL if called to decode a netmask */
/* Guess netmask */
a = (u_num32) ntohl(addr->s_addr);
if (!(a & 0xFFFFFFFFul))
mask->s_addr = htonl(0x00000000ul);
else if (!(a & 0x00FFFFFF))
mask->s_addr = htonl(0xFF000000ul);
else if (!(a & 0x0000FFFF))
mask->s_addr = htonl(0xFFFF0000ul);
else if (!(a & 0x000000FF))
mask->s_addr = htonl(0xFFFFFF00ul);
else
mask->s_addr = htonl(0xFFFFFFFFul);
}
return 1;
}
#define SCAN_ACL1
"%[0123456789.]-%[0123456789.]/%[0123456789.]"
#define SCAN_ACL2
"%[0123456789.]-%[0123456789.]%c"
#define SCAN_ACL3
"%[0123456789.]/%[0123456789.]"
#define SCAN_ACL4
"%[0123456789.]%c"
static acl_ip_data *
aclParseIpData(const char *t)
{
LOCAL_ARRAY(char, addr1, 256);
LOCAL_ARRAY(char, addr2, 256);
LOCAL_ARRAY(char, mask, 256);
acl_ip_data *q = memAllocate(MEM_ACL_IP_DATA);
acl_ip_data *r;
acl_ip_data **Q;
struct hostent *hp;
char **x;
char c;
debug(28, 5) ("aclParseIpData: %s\n", t);
if (!strcasecmp(t, "all")) {
q->addr1.s_addr = 0;
q->addr2.s_addr = 0;
q->mask.s_addr = 0;
return q;
}
if (sscanf(t, SCAN_ACL1, addr1, addr2, mask) == 3) {
(void) 0;
} else if (sscanf(t, SCAN_ACL2, addr1, addr2, &c) == 2) {
mask[0] = '\0';
} else if (sscanf(t, SCAN_ACL3, addr1, mask) == 2) {
addr2[0] = '\0';
} else if (sscanf(t, SCAN_ACL4, addr1, &c) == 1) {
addr2[0] = '\0';
mask[0] = '\0';
} else if (sscanf(t, "%[^/]/%s", addr1, mask) == 2) {
addr2[0] = '\0';
} else if (sscanf(t, "%s", addr1) == 1) {
/*
* Note, must use plain gethostbyname() here because at startup
* ipcache hasn't been initialized
*/
if ((hp = gethostbyname(addr1)) == NULL) {
debug(28, 0) ("aclParseIpData: Bad host/IP: '%s'\n", t);
safe_free(q);
return NULL;
}
Q = &q;
for (x = hp->h_addr_list; x != NULL && *x != NULL; x++) {
if ((r = *Q) == NULL)
r = *Q = memAllocate(MEM_ACL_IP_DATA);
xmemcpy(&r->addr1.s_addr, *x, sizeof(r->addr1.s_addr));
r->addr2.s_addr = 0;
r->mask.s_addr = no_addr.s_addr;
/* 255.255.255.255 */
Q = &r->next;
debug(28, 3) ("%s --> %s\n", addr1, inet_ntoa(r->addr1));
}
return q;
} else {
debug(28, 0) ("aclParseIpData: Bad host/IP: '%s'\n", t);
safe_free(q);
return NULL;
}
/* Decode addr1 */
if (!decode_addr(addr1, &q->addr1, &q->mask)) {
debug(28, 0) ("%s line %d: %s\n",
cfg_filename, config_lineno, config_input_line);
debug(28, 0) ("aclParseIpData: Ignoring invalid IP acl entry: unknown first address
'%s'\n", addr1);
safe_free(q);
return NULL;
}
/* Decode addr2 */
if (*addr2 && !decode_addr(addr2, &q->addr2, &q->mask)) {
debug(28, 0) ("%s line %d: %s\n",
cfg_filename, config_lineno, config_input_line);
debug(28, 0) ("aclParseIpData: Ignoring invalid IP acl entry: unknown second
address '%s'\n", addr2);
safe_free(q);
return NULL;
}
/* Decode mask */
if (*mask && !decode_addr(mask, &q->mask, NULL)) {
debug(28, 0) ("%s line %d: %s\n",
cfg_filename, config_lineno, config_input_line);
debug(28, 0) ("aclParseIpData: Ignoring invalid IP acl entry: unknown netmask
'%s'\n", mask);
safe_free(q);
return NULL;
}
if ((q->addr1.s_addr & q->mask.s_addr) != q->addr1.s_addr ||
(q->addr2.s_addr & q->mask.s_addr) != q->addr2.s_addr)
debug(28, 0) ("aclParseIpData: WARNING: Netmask masks away part of the
specified IP in '%s'\n", t);
q->addr1.s_addr &= q->mask.s_addr;
q->addr2.s_addr &= q->mask.s_addr;
/* 1.2.3.4/255.255.255.0 --> 1.2.3.0 */
return q;
}
/******************/
/* aclParseIpList */
/******************/
static void
aclParseIpList(void *curlist)
{
char *t = NULL;
splayNode **Top = curlist;
acl_ip_data *q = NULL;
while ((t = strtokFile())) {
q = aclParseIpData(t);
while (q != NULL) {
*Top = splay_insert(q, *Top, aclIpNetworkCompare);
q = q->next;
}
}
}
static void
aclParseTimeSpec(void *curlist)
{
acl_time_data *q = NULL;
acl_time_data **Tail;
int h1, m1, h2, m2;
char *t = NULL;
long weekbits = 0;
for (Tail = curlist; *Tail; Tail = &((*Tail)->next));
while ((t = strtokFile())) {
if (*t < '0' || *t > '9') {
/* assume its day-of-week spec */
while (*t) {
switch (*t++) {
case 'S':
weekbits |= ACL_SUNDAY;
break;
case 'M':
weekbits |= ACL_MONDAY;
break;
case 'T':
weekbits |= ACL_TUESDAY;
break;
case 'W':
weekbits |= ACL_WEDNESDAY;
break;
case 'H':
weekbits |= ACL_THURSDAY;
break;
case 'F':
weekbits |= ACL_FRIDAY;
break;
case 'A':
weekbits |= ACL_SATURDAY;
break;
case 'D':
weekbits |= ACL_WEEKDAYS;
break;
case '-':
/* ignore placeholder */
break;
default:
debug(28, 0) ("%s line %d: %s\n",
cfg_filename, config_lineno, config_input_line);
debug(28, 0) ("aclParseTimeSpec: Bad Day '%c'\n", *t);
break;
}
}
} else {
/* assume its time-of-day spec */
if (sscanf(t, "%d:%d-%d:%d", &h1, &m1, &h2, &m2) < 4) {
debug(28, 0) ("%s line %d: %s\n",
cfg_filename, config_lineno, config_input_line);
debug(28, 0) ("aclParseTimeSpec: IGNORING Bad time range\n");
memFree(q, MEM_ACL_TIME_DATA);
return;
}
q = memAllocate(MEM_ACL_TIME_DATA);
q->start = h1 * 60 + m1;
q->stop = h2 * 60 + m2;
q->weekbits = weekbits;
weekbits = 0;
if (q->start > q->stop) {
debug(28, 0) ("%s line %d: %s\n",
cfg_filename, config_lineno, config_input_line);
debug(28, 0) ("aclParseTimeSpec: IGNORING Reversed time range\n");
memFree(q, MEM_ACL_TIME_DATA);
return;
}
if (q->weekbits == 0)
q->weekbits = ACL_ALLWEEK;
*(Tail) = q;
Tail = &q->next;
}
}
if (weekbits) {
q = memAllocate(MEM_ACL_TIME_DATA);
q->start = 0 * 60 + 0;
q->stop = 24 * 60 + 0;
q->weekbits = weekbits;
*(Tail) = q;
Tail = &q->next;
}
}
void
aclParseRegexList(void *curlist)
{
relist **Tail;
relist *q = NULL;
char *t = NULL;
regex_t comp;
int errcode;
int flags = REG_EXTENDED | REG_NOSUB;
for (Tail = curlist; *Tail; Tail = &((*Tail)->next));
while ((t = strtokFile())) {
if (strcmp(t, "-i") == 0) {
flags |= REG_ICASE;
continue;
}
if (strcmp(t, "+i") == 0) {
flags &= ~REG_ICASE;
continue;
}
if ((errcode = regcomp(&comp, t, flags)) != 0) {
char errbuf[256];
regerror(errcode, &comp, errbuf, sizeof errbuf);
debug(28, 0) ("%s line %d: %s\n",
cfg_filename, config_lineno, config_input_line);
debug(28, 0) ("aclParseRegexList: Invalid regular expression '%s': %s\n",
t, errbuf);
continue;
}
q = memAllocate(MEM_RELIST);
q->pattern = xstrdup(t);
q->regex = comp;
*(Tail) = q;
Tail = &q->next;
}
}
static void
aclParseHeader(void *data)
{
char *t;
acl_hdr_data **hd = data;
acl_hdr_data *q;
t = strtokFile();
if (NULL == t) {
debug(28, 0) ("%s line %d: %s\n", cfg_filename, config_lineno, config_input_line);
debug(28, 0) ("aclParseHeader: No data defined '%s'\n", t);
return;
}
q = xcalloc(1, sizeof(acl_hdr_data));
q->hdr_name = xstrdup(t);
q->hdr_id = httpHeaderIdByNameDef(t, strlen(t));
aclParseRegexList(q->reglist);
if (!q->reglist) {
debug(28, 0) ("%s line %d: %s\n", cfg_filename, config_lineno, config_input_line);
debug(28, 0) ("aclParseHeader: No pattern defined '%s'\n", t);
aclDestroyHeader(&q);
return;
}
while (*hd)
hd = &(*hd)->next;
*hd = q;
}
static int
aclMatchHeader(acl_hdr_data * hdrs, const HttpHeader * hdr)
{
acl_hdr_data *hd;
for (hd = hdrs; hd; hd = hd->next) {
int ret;
String header;
if (hd->hdr_id != -1)
header = httpHeaderGetStrOrList(hdr, hd->hdr_id);
else
header = httpHeaderGetByName(hdr, hd->hdr_name);
if (!strBuf(header))
continue;
ret = aclMatchRegex(hd->reglist, strBuf(header));
stringClean(&header);
if (ret)
return 1;
}
return 0;
}
void
aclDestroyHeader(void *data)
{
acl_hdr_data **acldata = data;
while (*acldata) {
acl_hdr_data *q = *acldata;
*acldata = q->next;
if (q->reglist)
aclDestroyRegexList((*acldata)->reglist);
safe_free(q);
}
}
static wordlist *
aclDumpHeader(acl_hdr_data * hd)
{
wordlist *W = NULL;
relist *data = hd->reglist;
wordlistAdd(&W, httpHeaderNameById(hd->hdr_id));
while (data != NULL) {
wordlistAdd(&W, data->pattern);
data = data->next;
}
return aclDumpRegexList(hd->reglist);
}
#if SQUID_SNMP
static void
aclParseWordList(void *curlist)
{
char *t = NULL;
while ((t = strtokFile()))
wordlistAdd(curlist, t);
}
#endif
static void
aclParseUserList(void **current)
{
char *t = NULL;
acl_user_data *data;
splayNode *Top = NULL;
debug(28, 2) ("aclParseUserList: parsing user list\n");
t = strtokFile();
if (!t) {
debug(28, 2) ("aclParseUserList: No data defined\n");
return;
}
debug(28, 5) ("aclParseUserList: First token is %s\n", t);
if (*current == NULL) {
debug(28, 3) ("aclParseUserList: current is null. Creating\n");
*current = memAllocate(MEM_ACL_USER_DATA);
}
data = *current;
Top = data->names;
if (strcmp("-i", t) == 0) {
debug(28, 5) ("aclParseUserList: Going case-insensitive\n");
data->flags.case_insensitive = 1;
} else if (strcmp("REQUIRED", t) == 0) {
debug(28, 5) ("aclParseUserList: REQUIRED-type enabled\n");
data->flags.required = 1;
} else {
if (data->flags.case_insensitive)
Tolower(t);
Top = splay_insert(xstrdup(t), Top, (SPLAYCMP *) strcmp);
}
debug(28, 3) ("aclParseUserList: Case-insensitive-switch is %d\n",
data->flags.case_insensitive);
/* we might inherit from a previous declaration */
debug(28, 4) ("aclParseUserList: parsing user list\n");
while ((t = strtokFile())) {
debug(28, 6) ("aclParseUserList: Got token: %s\n", t);
if (data->flags.case_insensitive)
Tolower(t);
Top = splay_insert(xstrdup(t), Top, (SPLAYCMP *) strcmp);
}
data->names = Top;
}
/**********************/
/* aclParseDomainList */
/**********************/
static void
aclParseDomainList(void *curlist)
{
char *t = NULL;
splayNode **Top = curlist;
while ((t = strtokFile())) {
Tolower(t);
*Top = splay_insert(xstrdup(t), *Top, aclDomainCompare);
}
}
void
aclParseAclLine(acl ** head)
{
/* we're already using strtok() to grok the line */
char *t = NULL;
acl *A = NULL;
LOCAL_ARRAY(char, aclname, ACL_NAME_SZ);
squid_acl acltype;
int new_acl = 0;
/* snarf the ACL name */
if ((t = strtok(NULL, w_space)) == NULL) {
debug(28, 0) ("%s line %d: %s\n",
cfg_filename, config_lineno, config_input_line);
debug(28, 0) ("aclParseAclLine: missing ACL name.\n");
return;
}
xstrncpy(aclname, t, ACL_NAME_SZ);
/* snarf the ACL type */
if ((t = strtok(NULL, w_space)) == NULL) {
debug(28, 0) ("%s line %d: %s\n",
cfg_filename, config_lineno, config_input_line);
debug(28, 0) ("aclParseAclLine: missing ACL type.\n");
return;
}
if ((acltype = aclStrToType(t)) == ACL_NONE) {
debug(28, 0) ("%s line %d: %s\n",
cfg_filename, config_lineno, config_input_line);
debug(28, 0) ("aclParseAclLine: Invalid ACL type '%s'\n", t);
return;
}
if ((A = aclFindByName(aclname)) == NULL) {
debug(28, 3) ("aclParseAclLine: Creating ACL '%s'\n", aclname);
A = memAllocate(MEM_ACL);
xstrncpy(A->name, aclname, ACL_NAME_SZ);
A->type = acltype;
A->cfgline = xstrdup(config_input_line);
new_acl = 1;
} else {
if (acltype != A->type) {
debug(28, 0) ("aclParseAclLine: ACL '%s' already exists with different type,
skipping.\n", A->name);
return;
}
debug(28, 3) ("aclParseAclLine: Appending to '%s'\n", aclname);
new_acl = 0;
}
/*
* Here we set AclMatchedName in case we need to use it in a
* warning message in aclDomainCompare().
*/
AclMatchedName = aclname; /* ugly */
switch (A->type) {
case ACL_SRC_IP:
case ACL_DST_IP:
case ACL_MY_IP:
aclParseIpList(&A->data);
break;
case ACL_SRC_DOMAIN:
case ACL_DST_DOMAIN:
aclParseDomainList(&A->data);
break;
case ACL_TIME:
aclParseTimeSpec(&A->data);
break;
case ACL_URL_REGEX:
case ACL_URLLOGIN:
case ACL_URLPATH_REGEX:
case ACL_BROWSER:
case ACL_REFERER_REGEX:
case ACL_SRC_DOM_REGEX:
case ACL_DST_DOM_REGEX:
case ACL_REQ_MIME_TYPE:
case ACL_REP_MIME_TYPE:
aclParseRegexList(&A->data);
break;
case ACL_REP_HEADER:
case ACL_REQ_HEADER:
aclParseHeader(&A->data);
break;
case ACL_SRC_ASN:
case ACL_MAXCONN:
case ACL_DST_ASN:
aclParseIntlist(&A->data);
break;
case ACL_MAX_USER_IP:
aclParseUserMaxIP(&A->data);
break;
#if SRC_RTT_NOT_YET_FINISHED
case ACL_NETDB_SRC_RTT:
aclParseIntlist(&A->data);
break;
#endif
case ACL_URL_PORT:
case ACL_MY_PORT:
aclParseIntRange(&A->data);
break;
#if USE_IDENT
case ACL_IDENT:
aclParseUserList(&A->data);
break;
case ACL_IDENT_REGEX:
aclParseRegexList(&A->data);
break;
#endif
case ACL_PROTO:
aclParseProtoList(&A->data);
break;
case ACL_METHOD:
aclParseMethodList(&A->data);
break;
case ACL_PROXY_AUTH:
if (authenticateSchemeCount() == 0) {
debug(28, 0) ("aclParseAclLine: IGNORING: Proxy Auth ACL '%s' \
because no authentication schemes were compiled.\n", A->cfgline);
} else if (authenticateActiveSchemeCount() == 0) {
debug(28, 0) ("aclParseAclLine: IGNORING: Proxy Auth ACL '%s' \
because no authentication schemes are fully configured.\n", A->cfgline);
} else {
aclParseUserList(&A->data);
}
break;
case ACL_PROXY_AUTH_REGEX:
if (authenticateSchemeCount() == 0) {
debug(28, 0) ("aclParseAclLine: IGNORING: Proxy Auth ACL '%s' \
because no authentication schemes were compiled.\n", A->cfgline);
} else if (authenticateActiveSchemeCount() == 0) {
debug(28, 0) ("aclParseAclLine: IGNORING: Proxy Auth ACL '%s' \
because no authentication schemes are fully configured.\n", A->cfgline);
} else {
aclParseRegexList(&A->data);
}
break;
#if SQUID_SNMP
case ACL_SNMP_COMMUNITY:
aclParseWordList(&A->data);
break;
#endif
#if USE_ARP_ACL
case ACL_SRC_ARP:
aclParseArpList(&A->data);
break;
#endif
case ACL_EXTERNAL:
aclParseExternal(&A->data);
break;
case ACL_NONE:
case ACL_ENUM_MAX:
fatal("Bad ACL type");
break;
}
/*
* Clear AclMatchedName from our temporary hack
*/
AclMatchedName = NULL;
/* ugly */
if (!new_acl)
return;
if (A->data == NULL) {
debug(28, 0) ("aclParseAclLine: IGNORING invalid ACL: %s\n",
A->cfgline);
memFree(A, MEM_ACL);
return;
}
/* append */
while (*head)
head = &(*head)->next;
*head = A;
}
/* does name lookup, returns page_id */
err_type
aclGetDenyInfoPage(acl_deny_info_list ** head, const char *name)
{
acl_deny_info_list *A = NULL;
acl_name_list *L = NULL;
A = *head;
if (NULL == *head)
/* empty list */
return ERR_NONE;
while (A) {
L = A->acl_list;
if (NULL == L)
/* empty list should never happen, but in case */
continue;
while (L) {
if (!strcmp(name, L->name))
return A->err_page_id;
L = L->next;
}
A = A->next;
}
return ERR_NONE;
}
/* does name lookup, returns if it is a proxy_auth acl */
int
aclIsProxyAuth(const char *name)
{
acl *a;
if (NULL == name)
return 0;
if ((a = aclFindByName(name)))
return a->type == ACL_PROXY_AUTH || a->type == ACL_PROXY_AUTH_REGEX;
return 0;
}
/* [email protected] (05.09.96)
*
get the info for redirecting "access denied" to info pages
*
TODO (probably ;-)
*
currently there is no optimization for
*
- more than one deny_info line with the same url
*
- a check, whether the given acl really is defined
*
- a check, whether an acl is added more than once for the same url
*/
void
aclParseDenyInfoLine(acl_deny_info_list ** head)
{
char *t = NULL;
acl_deny_info_list *A = NULL;
acl_deny_info_list *B = NULL;
acl_deny_info_list **T = NULL;
acl_name_list *L = NULL;
acl_name_list **Tail = NULL;
/* first expect a page name */
if ((t = strtok(NULL, w_space)) == NULL) {
debug(28, 0) ("%s line %d: %s\n",
cfg_filename, config_lineno, config_input_line);
debug(28, 0) ("aclParseDenyInfoLine: missing 'error page' parameter.\n");
return;
}
A = memAllocate(MEM_ACL_DENY_INFO_LIST);
A->err_page_id = errorReservePageId(t);
A->err_page_name = xstrdup(t);
A->next = (acl_deny_info_list *) NULL;
/* next expect a list of ACL names */
Tail = &A->acl_list;
while ((t = strtok(NULL, w_space))) {
L = memAllocate(MEM_ACL_NAME_LIST);
xstrncpy(L->name, t, ACL_NAME_SZ);
*Tail = L;
Tail = &L->next;
}
if (A->acl_list == NULL) {
debug(28, 0) ("%s line %d: %s\n",
cfg_filename, config_lineno, config_input_line);
debug(28,
0)
("aclParseDenyInfoLine:
deny_info
line
contains
skipping\n");
memFree(A, MEM_ACL_DENY_INFO_LIST);
return;
}
for (B = *head, T = head; B; T = &B->next, B = B->next); /* find the tail */
*T = A;
}
void
aclParseAccessLine(acl_access ** head)
{
char *t = NULL;
acl_access *A = NULL;
acl_access *B = NULL;
acl_access **T = NULL;
/* first expect either 'allow' or 'deny' */
if ((t = strtok(NULL, w_space)) == NULL) {
debug(28, 0) ("%s line %d: %s\n",
cfg_filename, config_lineno, config_input_line);
debug(28, 0) ("aclParseAccessLine: missing 'allow' or 'deny'.\n");
return;
}
no
ACL's,
A = cbdataAlloc(acl_access);
if (!strcmp(t, "allow"))
A->allow = 1;
else if (!strcmp(t, "deny"))
A->allow = 0;
else {
debug(28, 0) ("%s line %d: %s\n",
cfg_filename, config_lineno, config_input_line);
debug(28, 0) ("aclParseAccessLine: expecting 'allow' or 'deny', got '%s'.\n", t);
cbdataFree(A);
return;
}
aclParseAclList(&A->acl_list);
if (A->acl_list == NULL) {
debug(28, 0) ("%s line %d: %s\n",
cfg_filename, config_lineno, config_input_line);
debug(28, 0) ("aclParseAccessLine: Access line contains no ACL's, skipping\n");
cbdataFree(A);
return;
}
A->cfgline = xstrdup(config_input_line);
/* Append to the end of this list */
for (B = *head, T = head; B; T = &B->next, B = B->next);
*T = A;
/* We lock _acl_access structures in aclCheck() */
}
void
aclParseAclList(acl_list ** head)
{
acl_list *L = NULL;
acl_list **Tail = head;
acl *a = NULL;
char *t;
/* sane name in the use below */
/* next expect a list of ACL names, possibly preceeded
* by '!' for negation */
while ((t = strtok(NULL, w_space))) {
L = memAllocate(MEM_ACL_LIST);
L->op = 1;
/* defaults to non-negated */
if (*t == '!') {
/* negated ACL */
L->op = 0;
t++;
}
debug(28, 3) ("aclParseAccessLine: looking for ACL name '%s'\n", t);
a = aclFindByName(t);
if (a == NULL) {
debug(28, 0) ("%s line %d: %s\n",
cfg_filename, config_lineno, config_input_line);
debug(28, 0) ("aclParseAccessLine: ACL name '%s' not found.\n", t);
memFree(L, MEM_ACL_LIST);
continue;
}
L->acl = a;
*Tail = L;
Tail = &L->next;
}
}
/**************/
/* aclMatchIp */
/**************/
static int
aclMatchIp(void *dataptr, struct in_addr c)
{
splayNode **Top = dataptr;
acl_ip_data x;
/*
* aclIpAddrNetworkCompare() takes two acl_ip_data pointers as
* arguments, so we must create a fake one for the client's IP
* address, and use a /32 netmask. However, the current code
* probably only accesses the addr1 element of this argument,
* so it might be possible to leave addr2 and mask unset.
* XXX Could eliminate these repetitive assignments with a
* static structure.
*/
x.addr1 = c;
x.addr2 = any_addr;
x.mask = no_addr;
x.next = NULL;
*Top = splay_splay(&x, *Top, aclIpAddrNetworkCompare);
debug(28, 3) ("aclMatchIp: '%s' %s\n",
inet_ntoa(c), splayLastResult ? "NOT found" : "found");
return !splayLastResult;
}
/**********************/
/* aclMatchDomainList */
/**********************/
static int
aclMatchDomainList(void *dataptr, const char *host)
{
splayNode **Top = dataptr;
if (host == NULL)
return 0;
debug(28, 3) ("aclMatchDomainList: checking '%s'\n", host);
*Top = splay_splay(host, *Top, aclHostDomainCompare);
debug(28, 3) ("aclMatchDomainList: '%s' %s\n",
host, splayLastResult ? "NOT found" : "found");
return !splayLastResult;
}
int
aclMatchRegex(relist * data, const char *word)
{
relist *first, *prev;
if (word == NULL)
return 0;
debug(28, 3) ("aclMatchRegex: checking '%s'\n", word);
first = data;
prev = NULL;
while (data) {
debug(28, 3) ("aclMatchRegex: looking for '%s'\n", data->pattern);
if (regexec(&data->regex, word, 0, 0, 0) == 0) {
if (prev != NULL) {
/* shift the element just found to the second position
* in the list */
prev->next = data->next;
data->next = first->next;
first->next = data;
}
return 1;
}
prev = data;
data = data->next;
}
return 0;
}
static int
aclMatchUser(void *proxyauth_acl, char *user)
{
acl_user_data *data = (acl_user_data *) proxyauth_acl;
splayNode *Top = data->names;
debug(28, 7) ("aclMatchUser: user is %s, case_insensitive is %d\n",
user, data->flags.case_insensitive);
debug(28, 8) ("Top is %p, Top->data is %s\n", Top,
(char *) (Top != NULL ? (Top)->data : "Unavailable"));
if (user == NULL || strcmp(user, "-") == 0)
return 0;
if (data->flags.required) {
debug(28, 7) ("aclMatchUser: user REQUIRED and auth-info present.\n");
return 1;
}
if (data->flags.case_insensitive)
Top = splay_splay(user, Top, (SPLAYCMP *) strcasecmp);
else
Top = splay_splay(user, Top, (SPLAYCMP *) strcmp);
/* Top=splay_splay(user,Top,(SPLAYCMP *)dumping_strcmp); */
debug(28, 7) ("aclMatchUser: returning %d,Top is %p, Top->data is %s\n",
!splayLastResult, Top, (char *) (Top ? Top->data : "Unavailable"));
data->names = Top;
return !splayLastResult;
}
/* ACL result caching routines */
/*
* we lookup an acl's cached results, and if we cannot find the acl being
* checked we check it and cache the result. This function is deliberatly
* generic to support caching of multiple acl types (but it needs to be more
* generic still....
* The Match Param and the cache MUST be tied together by the calling routine.
* You have been warned :-]
* Also only Matchxxx that are of the form (void *, void *) can be used.
* probably some ugly overloading _could_ be done but I'll leave that as an
* exercise for the reader. Note that caching of time based acl's is not
* wise due to no expiry occuring to the cache entries until the user expires
* or a reconfigure takes place.
* RBC
*/
static int
aclCacheMatchAcl(dlink_list * cache, squid_acl acltype, void *data,
char *MatchParam)
{
int matchrv;
acl_proxy_auth_match_cache *auth_match;
dlink_node *link;
link = cache->head;
while (link) {
auth_match = link->data;
if (auth_match->acl_data == data) {
debug(28, 4) ("aclCacheMatchAcl: cache hit on acl '%p'\n", data);
return auth_match->matchrv;
}
link = link->next;
}
auth_match = NULL;
/* match the user in the acl. They are not cached. */
switch (acltype) {
case ACL_PROXY_AUTH:
matchrv = aclMatchUser(data, MatchParam);
break;
case ACL_PROXY_AUTH_REGEX:
matchrv = aclMatchRegex(data, MatchParam);
break;
default:
/* This is a fatal to ensure that aclCacheMatchAcl calls are _only_
* made for supported acl types */
fatal("aclCacheMatchAcl: unknown or unexpected ACL type");
return 0;
/* NOTREACHED */
}
auth_match = memAllocate(MEM_ACL_PROXY_AUTH_MATCH);
auth_match->matchrv = matchrv;
auth_match->acl_data = data;
dlinkAddTail(auth_match, &auth_match->link, cache);
return matchrv;
}
void
aclCacheMatchFlush(dlink_list * cache)
{
acl_proxy_auth_match_cache *auth_match;
dlink_node *link, *tmplink;
link = cache->head;
while (link) {
auth_match = link->data;
tmplink = link;
link = link->next;
dlinkDelete(tmplink, cache);
memFree(auth_match, MEM_ACL_PROXY_AUTH_MATCH);
}
}
/* aclMatchProxyAuth can return two exit codes:
* 0 : Authorisation for this ACL failed. (Did not match)
* 1 : Authorisation OK. (Matched)
*/
static int
aclMatchProxyAuth(void *data, auth_user_request_t * auth_user_request,
aclCheck_t * checklist, squid_acl acltype)
{
/* checklist is used to register user name when identified, nothing else */
/* General program flow in proxy_auth acls
* 1. Consistency checks: are we getting sensible data
* 2. Call the authenticate* functions to establish a authenticated user
* 4. look up the username in acltype (and cache the result against the
*
username
*/
/* for completeness */
authenticateAuthUserRequestLock(auth_user_request);
/* consistent parameters ? */
assert(authenticateUserAuthenticated(auth_user_request));
/* this ACL check completed */
authenticateAuthUserRequestUnlock(auth_user_request);
/* check to see if we have matched the user-acl before */
return aclCacheMatchAcl(&auth_user_request->auth_user->
proxy_match_cache, acltype, data,
authenticateUserRequestUsername(auth_user_request));
}
CBDATA_TYPE(acl_user_ip_data);
void
aclParseUserMaxIP(void *data)
{
acl_user_ip_data **acldata = data;
char *t = NULL;
CBDATA_INIT_TYPE(acl_user_ip_data);
if (*acldata) {
debug(28, 1) ("Attempting to alter already set User max IP acl\n");
return;
}
*acldata = cbdataAlloc(acl_user_ip_data);
t = strtokFile();
if (!t)
goto error;
debug(28, 5) ("aclParseUserMaxIP: First token is %s\n", t);
if (strcmp("-s", t) == 0) {
debug(28, 5) ("aclParseUserMaxIP: Going strict\n");
(*acldata)->flags.strict = 1;
t = strtokFile();
if (!t)
goto error;
}
(*acldata)->max = atoi(t);
debug(28, 5) ("aclParseUserMaxIP: Max IP address's %d\n", (int) (*acldata)->max);
return;
error:
fatal("aclParseUserMaxIP: Malformed ACL %d\n");
}
void
aclDestroyUserMaxIP(void *data)
{
acl_user_ip_data **acldata = data;
if (*acldata)
cbdataFree(*acldata);
*acldata = NULL;
}
wordlist *
aclDumpUserMaxIP(void *data)
{
acl_user_ip_data *acldata = data;
wordlist *W = NULL;
char buf[128];
if (acldata->flags.strict)
wordlistAdd(&W, "-s");
snprintf(buf, sizeof(buf), "%lu", (unsigned long int) acldata->max);
wordlistAdd(&W, buf);
return W;
}
/*
* aclMatchUserMaxIP - check for users logging in from multiple IP's
* 0 : No match
* 1 : Match
*/
int
aclMatchUserMaxIP(void *data, auth_user_request_t * auth_user_request,
struct in_addr src_addr)
{
/*
* the logic for flush the ip list when the limit is hit vs keep
* it sorted in most recent access order and just drop the oldest
* one off is currently undecided
*/
acl_user_ip_data *acldata = data;
if (authenticateAuthUserRequestIPCount(auth_user_request) <= acldata->max)
return 0;
/* this is a match */
if (acldata->flags.strict) {
/*
* simply deny access - the user name is already associated with
* the request
*/
/* remove _this_ ip, as it is the culprit for going over the limit */
authenticateAuthUserRequestRemoveIp(auth_user_request, src_addr);
debug(28, 4) ("aclMatchUserMaxIP: Denying access in strict mode\n");
} else {
/*
* non-strict - remove some/all of the cached entries
* ie to allow the user to move machines easily
*/
authenticateAuthUserRequestClearIp(auth_user_request);
debug(28, 4) ("aclMatchUserMaxIP: Denying access in non-strict mode - flushing
the user ip cache\n");
}
return 1;
}
static void
aclLookupProxyAuthStart(aclCheck_t * checklist)
{
auth_user_request_t *auth_user_request;
/* make sure someone created auth_user_request for us */
assert(checklist->auth_user_request != NULL);
auth_user_request = checklist->auth_user_request;
assert(authenticateValidateUser(auth_user_request));
authenticateStart(auth_user_request, aclLookupProxyAuthDone, checklist);
}
static int
aclMatchInteger(intlist * data, int i)
{
intlist *first, *prev;
first = data;
prev = NULL;
while (data) {
if (data->i == i) {
if (prev != NULL) {
/* shift the element just found to the second position
* in the list */
prev->next = data->next;
data->next = first->next;
first->next = data;
}
return 1;
}
prev = data;
data = data->next;
}
return 0;
}
static int
aclMatchIntegerRange(intrange * data, int i)
{
intrange *first, *prev;
first = data;
prev = NULL;
while (data) {
if (i < data->i) {
(void) 0;
} else if (i > data->j) {
(void) 0;
} else {
/* matched */
if (prev != NULL) {
/* shift the element just found to the second position
* in the list */
prev->next = data->next;
data->next = first->next;
first->next = data;
}
return 1;
}
prev = data;
data = data->next;
}
return 0;
}
static int
aclMatchTime(acl_time_data * data, time_t when)
{
static time_t last_when = 0;
static struct tm tm;
time_t t;
assert(data != NULL);
if (when != last_when) {
last_when = when;
xmemcpy(&tm, localtime(&when), sizeof(struct tm));
}
t = (time_t) (tm.tm_hour * 60 + tm.tm_min);
debug(28, 3) ("aclMatchTime: checking %d in %d-%d, weekbits=%x\n",
(int) t, (int) data->start, (int) data->stop, data->weekbits);
while (data) {
if (t >= data->start && t <= data->stop && (data->weekbits & (1 << tm.tm_wday)))
return 1;
data = data->next;
}
return 0;
}
#if SQUID_SNMP
static int
aclMatchWordList(wordlist * w, const char *word)
{
debug(28, 3) ("aclMatchWordList: looking for '%s'\n", word);
while (w != NULL) {
debug(28, 3) ("aclMatchWordList: checking '%s'\n", w->key);
if (!strcmp(w->key, word))
return 1;
w = w->next;
}
return 0;
}
#endif
int
aclAuthenticated(aclCheck_t * checklist)
{
request_t *r = checklist->request;
http_hdr_type headertype;
if (NULL == r) {
return -1;
} else if (!r->flags.accelerated) {
/* Proxy authorization on proxy requests */
headertype = HDR_PROXY_AUTHORIZATION;
} else if (r->flags.internal) {
/* WWW authorization on accelerated internal requests */
headertype = HDR_AUTHORIZATION;
} else {
#if AUTH_ON_ACCELERATION
/* WWW authorization on accelerated requests */
headertype = HDR_AUTHORIZATION;
#else
debug(28, 1) ("aclAuthenticated: authentication not applicable on accelerated
requests.\n");
return -1;
#endif
}
/* get authed here */
/* Note: this fills in checklist->auth_user_request when applicable (auth incomplete) */
switch (authenticateTryToAuthenticateAndSetAuthUser(&checklist->auth_user_request,
headertype, checklist->request, checklist->conn, checklist->src_addr)) {
case AUTH_ACL_CANNOT_AUTHENTICATE:
debug(28, 4) ("aclMatchAcl: returning 0 user authenticated but not authorised.\n");
return 0;
case AUTH_AUTHENTICATED:
if (checklist->auth_user_request) {
authenticateAuthUserRequestUnlock(checklist->auth_user_request);
checklist->auth_user_request = NULL;
}
return 1;
break;
case AUTH_ACL_HELPER:
debug(28, 4) ("aclMatchAcl: returning 0 sending credentials to helper.\n");
checklist->state[ACL_PROXY_AUTH] = ACL_LOOKUP_NEEDED;
return -1;
case AUTH_ACL_CHALLENGE:
debug(28, 4) ("aclMatchAcl: returning 0 sending authentication challenge.\n");
checklist->state[ACL_PROXY_AUTH] = ACL_PROXY_AUTH_NEEDED;
return -1;
default:
fatal("unexpected authenticateAuthenticate reply\n");
return -1;
}
}
static int
aclMatchAcl(acl * ae, aclCheck_t * checklist)
{
request_t *r = checklist->request;
const ipcache_addrs *ia = NULL;
const char *fqdn = NULL;
char *esc_buf;
const char *header;
const char *browser;
int k, ti;
if (!ae)
return 0;
switch (ae->type) {
case ACL_BROWSER:
case ACL_REFERER_REGEX:
case ACL_DST_ASN:
case ACL_DST_DOMAIN:
case ACL_DST_DOM_REGEX:
case ACL_DST_IP:
case ACL_MAX_USER_IP:
case ACL_METHOD:
case ACL_PROTO:
case ACL_PROXY_AUTH:
case ACL_PROXY_AUTH_REGEX:
case ACL_REP_MIME_TYPE:
case ACL_REQ_MIME_TYPE:
case ACL_REP_HEADER:
case ACL_REQ_HEADER:
case ACL_URLPATH_REGEX:
case ACL_URL_PORT:
case ACL_URL_REGEX:
case ACL_URLLOGIN:
/* These ACL types require checklist->request */
if (NULL == r) {
debug(28, 1) ("WARNING: '%s' ACL is used but there is no"
" HTTP request -- access denied.\n", ae->name);
return 0;
}
break;
default:
break;
}
debug(28, 3) ("aclMatchAcl: checking '%s'\n", ae->cfgline);
switch (ae->type) {
case ACL_SRC_IP:
return aclMatchIp(&ae->data, checklist->src_addr);
/* NOTREACHED */
case ACL_MY_IP:
return aclMatchIp(&ae->data, checklist->my_addr);
/* NOTREACHED */
case ACL_DST_IP:
ia = ipcache_gethostbyname(r->host, IP_LOOKUP_IF_MISS);
if (ia) {
for (k = 0; k < (int) ia->count; k++) {
if (aclMatchIp(&ae->data, ia->in_addrs[k]))
return 1;
}
return 0;
} else if (checklist->state[ACL_DST_IP] == ACL_LOOKUP_NONE) {
debug(28, 3) ("aclMatchAcl: Can't yet compare '%s' ACL for '%s'\n",
ae->name, r->host);
checklist->state[ACL_DST_IP] = ACL_LOOKUP_NEEDED;
return 0;
} else {
return aclMatchIp(&ae->data, no_addr);
}
/* NOTREACHED */
case ACL_DST_DOMAIN:
if ((ia = ipcacheCheckNumeric(r->host)) == NULL)
return aclMatchDomainList(&ae->data, r->host);
fqdn = fqdncache_gethostbyaddr(ia->in_addrs[0], FQDN_LOOKUP_IF_MISS);
if (fqdn)
return aclMatchDomainList(&ae->data, fqdn);
if (checklist->state[ACL_DST_DOMAIN] == ACL_LOOKUP_NONE) {
debug(28, 3) ("aclMatchAcl: Can't yet compare '%s' ACL for '%s'\n",
ae->name, inet_ntoa(ia->in_addrs[0]));
checklist->state[ACL_DST_DOMAIN] = ACL_LOOKUP_NEEDED;
return 0;
}
return aclMatchDomainList(&ae->data, "none");
/* NOTREACHED */
case ACL_SRC_DOMAIN:
fqdn = fqdncache_gethostbyaddr(checklist->src_addr, FQDN_LOOKUP_IF_MISS);
if (fqdn) {
return aclMatchDomainList(&ae->data, fqdn);
} else if (checklist->state[ACL_SRC_DOMAIN] == ACL_LOOKUP_NONE) {
debug(28, 3) ("aclMatchAcl: Can't yet compare '%s' ACL for '%s'\n",
ae->name, inet_ntoa(checklist->src_addr));
checklist->state[ACL_SRC_DOMAIN] = ACL_LOOKUP_NEEDED;
return 0;
}
return aclMatchDomainList(&ae->data, "none");
/* NOTREACHED */
case ACL_DST_DOM_REGEX:
if ((ia = ipcacheCheckNumeric(r->host)) == NULL)
return aclMatchRegex(ae->data, r->host);
fqdn = fqdncache_gethostbyaddr(ia->in_addrs[0], FQDN_LOOKUP_IF_MISS);
if (fqdn)
return aclMatchRegex(ae->data, fqdn);
if (checklist->state[ACL_DST_DOMAIN] == ACL_LOOKUP_NONE) {
debug(28, 3) ("aclMatchAcl: Can't yet compare '%s' ACL for '%s'\n",
ae->name, inet_ntoa(ia->in_addrs[0]));
checklist->state[ACL_DST_DOMAIN] = ACL_LOOKUP_NEEDED;
return 0;
}
return aclMatchRegex(ae->data, "none");
/* NOTREACHED */
case ACL_SRC_DOM_REGEX:
fqdn = fqdncache_gethostbyaddr(checklist->src_addr, FQDN_LOOKUP_IF_MISS);
if (fqdn) {
return aclMatchRegex(ae->data, fqdn);
} else if (checklist->state[ACL_SRC_DOMAIN] == ACL_LOOKUP_NONE) {
debug(28, 3) ("aclMatchAcl: Can't yet compare '%s' ACL for '%s'\n",
ae->name, inet_ntoa(checklist->src_addr));
checklist->state[ACL_SRC_DOMAIN] = ACL_LOOKUP_NEEDED;
return 0;
}
return aclMatchRegex(ae->data, "none");
/* NOTREACHED */
case ACL_TIME:
return aclMatchTime(ae->data, squid_curtime);
/* NOTREACHED */
case ACL_URLPATH_REGEX:
esc_buf = xstrdup(strBuf(r->urlpath));
rfc1738_unescape(esc_buf);
k = aclMatchRegex(ae->data, esc_buf);
safe_free(esc_buf);
return k;
/* NOTREACHED */
case ACL_URL_REGEX:
esc_buf = xstrdup(urlCanonical(r));
rfc1738_unescape(esc_buf);
k = aclMatchRegex(ae->data, esc_buf);
safe_free(esc_buf);
return k;
case ACL_URLLOGIN:
esc_buf = xstrdup(r->login);
rfc1738_unescape(esc_buf);
k = aclMatchRegex(ae->data, esc_buf);
safe_free(esc_buf);
return k;
/* NOTREACHED */
case ACL_MAXCONN:
k = clientdbEstablished(checklist->src_addr, 0);
return ((k > ((intlist *) ae->data)->i) ? 1 : 0);
/* NOTREACHED */
case ACL_URL_PORT:
return aclMatchIntegerRange(ae->data, (int) r->port);
/* NOTREACHED */
case ACL_MY_PORT:
return aclMatchIntegerRange(ae->data, (int) checklist->my_port);
/* NOTREACHED */
#if USE_IDENT
case ACL_IDENT:
if (checklist->rfc931[0]) {
return aclMatchUser(ae->data, checklist->rfc931);
} else {
checklist->state[ACL_IDENT] = ACL_LOOKUP_NEEDED;
return 0;
}
/* NOTREACHED */
case ACL_IDENT_REGEX:
if (checklist->rfc931[0]) {
return aclMatchRegex(ae->data, checklist->rfc931);
} else {
checklist->state[ACL_IDENT] = ACL_LOOKUP_NEEDED;
return 0;
}
/* NOTREACHED */
#endif
case ACL_PROTO:
return aclMatchInteger(ae->data, r->protocol);
/* NOTREACHED */
case ACL_METHOD:
return aclMatchInteger(ae->data, r->method);
/* NOTREACHED */
case ACL_BROWSER:
browser = httpHeaderGetStr(&checklist->request->header, HDR_USER_AGENT);
if (NULL == browser)
return 0;
return aclMatchRegex(ae->data, browser);
/* NOTREACHED */
case ACL_REFERER_REGEX:
header = httpHeaderGetStr(&checklist->request->header, HDR_REFERER);
if (NULL == header)
return 0;
return aclMatchRegex(ae->data, header);
/* NOTREACHED */
case ACL_PROXY_AUTH:
case ACL_PROXY_AUTH_REGEX:
if ((ti = aclAuthenticated(checklist)) != 1)
return ti;
ti = aclMatchProxyAuth(ae->data, r->auth_user_request,
checklist, ae->type);
return ti;
/* NOTREACHED */
case ACL_MAX_USER_IP:
if ((ti = aclAuthenticated(checklist)) != 1)
return ti;
ti = aclMatchUserMaxIP(ae->data, r->auth_user_request,
checklist->src_addr);
return ti;
/* NOTREACHED */
#if SQUID_SNMP
case ACL_SNMP_COMMUNITY:
return aclMatchWordList(ae->data, checklist->snmp_community);
/* NOTREACHED */
#endif
case ACL_SRC_ASN:
return asnMatchIp(ae->data, checklist->src_addr);
/* NOTREACHED */
case ACL_DST_ASN:
ia = ipcache_gethostbyname(r->host, IP_LOOKUP_IF_MISS);
if (ia) {
for (k = 0; k < (int) ia->count; k++) {
if (asnMatchIp(ae->data, ia->in_addrs[k]))
return 1;
}
return 0;
} else if (checklist->state[ACL_DST_ASN] == ACL_LOOKUP_NONE) {
debug(28, 3) ("asnMatchAcl: Can't yet compare '%s' ACL for '%s'\n",
ae->name, r->host);
checklist->state[ACL_DST_ASN] = ACL_LOOKUP_NEEDED;
} else {
return asnMatchIp(ae->data, no_addr);
}
return 0;
/* NOTREACHED */
#if USE_ARP_ACL
case ACL_SRC_ARP:
return aclMatchArp(&ae->data, checklist->src_addr);
/* NOTREACHED */
#endif
case ACL_REQ_MIME_TYPE:
header = httpHeaderGetStr(&checklist->request->header,
HDR_CONTENT_TYPE);
if (NULL == header)
header = "";
return aclMatchRegex(ae->data, header);
/* NOTREACHED */
case ACL_REP_MIME_TYPE:
if (!checklist->reply)
return 0;
header = httpHeaderGetStr(&checklist->reply->header, HDR_CONTENT_TYPE);
if (NULL == header)
header = "";
return aclMatchRegex(ae->data, header);
/* NOTREACHED */
case ACL_REP_HEADER:
if (!checklist->reply)
return 0;
return aclMatchHeader(ae->data, &checklist->reply->header);
/* NOTREACHED */
case ACL_REQ_HEADER:
return aclMatchHeader(ae->data, &checklist->request->header);
/* NOTREACHED */
case ACL_EXTERNAL:
return aclMatchExternal(ae->data, checklist);
/* NOTREACHED */
case ACL_NONE:
case ACL_ENUM_MAX:
break;
}
debug(28, 0) ("aclMatchAcl: '%s' has bad type %d\n",
ae->name, ae->type);
return 0;
}
int
aclMatchAclList(const acl_list * list, aclCheck_t * checklist)
{
while (list) {
int answer;
checklist->current_acl = list->acl;
AclMatchedName = list->acl->name;
debug(28, 3) ("aclMatchAclList: checking %s%s\n",
list->op ? null_string : "!", list->acl->name);
answer = aclMatchAcl(list->acl, checklist);
#if NOT_SURE_THIS_IS_GOOD
/* This will make access denied if an acl cannot be evaluated.
* Normally Squid will just continue to the next rule
*/
if (answer < 0) {
debug(28, 3) ("aclMatchAclList: failure. returning -1\n");
return -1;
}
#endif
if (answer != list->op) {
debug(28, 3) ("aclMatchAclList: no match, returning 0\n");
return 0;
}
list = list->next;
}
debug(28, 3) ("aclMatchAclList: returning 1\n");
return 1;
}
static void
aclCheckCleanup(aclCheck_t * checklist)
{
/* Cleanup temporary stuff used by the ACL checking */
if (checklist->extacl_entry) {
cbdataUnlock(checklist->extacl_entry);
checklist->extacl_entry = NULL;
}
/* During reconfigure or if authentication is used in aclCheckFast without
* first being authenticated in http_access we can end up not finishing call
* sequences into the auth code. In such case we must make sure to forget
* the authentication state completely
*/
if (checklist->auth_user_request) {
authenticateAuthUserRequestUnlock(checklist->auth_user_request);
checklist->auth_user_request = NULL;
if (checklist->request) {
if (checklist->request->auth_user_request) {
authenticateAuthUserRequestUnlock(checklist->request>auth_user_request);
checklist->request->auth_user_request = NULL;
}
}
/* it might have been connection based */
if (checklist->conn) {
if (checklist->conn->auth_user_request) {
authenticateAuthUserRequestUnlock(checklist->conn->auth_user_request);
checklist->conn->auth_user_request = NULL;
}
assert(checklist->request);
checklist->conn->auth_type = AUTH_BROKEN;
}
}
checklist->current_acl = NULL;
}
int
aclCheckFast(const acl_access * A, aclCheck_t * checklist)
{
allow_t allow = ACCESS_DENIED;
int answer;
debug(28, 5) ("aclCheckFast: list: %p\n", A);
while (A) {
allow = A->allow;
answer = aclMatchAclList(A->acl_list, checklist);
if (answer) {
if (answer < 0)
return ACCESS_DENIED;
aclCheckCleanup(checklist);
return allow == ACCESS_ALLOWED;
}
A = A->next;
}
debug(28, 5) ("aclCheckFast: no matches, returning: %d\n", allow ==
ACCESS_DENIED);
aclCheckCleanup(checklist);
return allow == ACCESS_DENIED;
}
static void
aclCheck(aclCheck_t * checklist)
{
allow_t allow = ACCESS_DENIED;
const acl_access *A;
int match;
ipcache_addrs *ia;
while ((A = checklist->access_list) != NULL) {
/*
* If the _acl_access is no longer valid (i.e. its been
* freed because of a reconfigure), then bail on this
* access check. For now, return ACCESS_DENIED.
*/
if (!cbdataValid(A)) {
cbdataUnlock(A);
checklist->access_list = NULL;
break;
}
debug(28, 3) ("aclCheck: checking '%s'\n", A->cfgline);
allow = A->allow;
match = aclMatchAclList(A->acl_list, checklist);
if (match == -1)
allow = ACCESS_DENIED;
if (checklist->state[ACL_DST_IP] == ACL_LOOKUP_NEEDED) {
checklist->state[ACL_DST_IP] = ACL_LOOKUP_PENDING;
ipcache_nbgethostbyname(checklist->request->host,
aclLookupDstIPDone, checklist);
return;
} else if (checklist->state[ACL_DST_ASN] == ACL_LOOKUP_NEEDED) {
checklist->state[ACL_DST_ASN] = ACL_LOOKUP_PENDING;
ipcache_nbgethostbyname(checklist->request->host,
aclLookupDstIPforASNDone, checklist);
return;
} else if (checklist->state[ACL_SRC_DOMAIN] == ACL_LOOKUP_NEEDED) {
checklist->state[ACL_SRC_DOMAIN] = ACL_LOOKUP_PENDING;
fqdncache_nbgethostbyaddr(checklist->src_addr,
aclLookupSrcFQDNDone, checklist);
return;
} else if (checklist->state[ACL_DST_DOMAIN] == ACL_LOOKUP_NEEDED) {
ia = ipcacheCheckNumeric(checklist->request->host);
if (ia == NULL) {
checklist->state[ACL_DST_DOMAIN] = ACL_LOOKUP_DONE;
return;
}
checklist->dst_addr = ia->in_addrs[0];
checklist->state[ACL_DST_DOMAIN] = ACL_LOOKUP_PENDING;
fqdncache_nbgethostbyaddr(checklist->dst_addr,
aclLookupDstFQDNDone, checklist);
return;
} else if (checklist->state[ACL_PROXY_AUTH] == ACL_LOOKUP_NEEDED) {
debug(28, 3)
("aclCheck: checking password via authenticator\n");
aclLookupProxyAuthStart(checklist);
checklist->state[ACL_PROXY_AUTH] = ACL_LOOKUP_PENDING;
return;
} else if (checklist->state[ACL_PROXY_AUTH] == ACL_PROXY_AUTH_NEEDED)
{
/* Client is required to resend the request with correct authentication
* credentials. (This may be part of a stateful auth protocol.
* The request is denied.
*/
debug(28, 6) ("aclCheck: requiring Proxy Auth header.\n");
allow = ACCESS_REQ_PROXY_AUTH;
match = -1;
}
#if USE_IDENT
else if (checklist->state[ACL_IDENT] == ACL_LOOKUP_NEEDED) {
debug(28, 3) ("aclCheck: Doing ident lookup\n");
if (cbdataValid(checklist->conn)) {
identStart(&checklist->conn->me, &checklist->conn->peer,
aclLookupIdentDone, checklist);
checklist->state[ACL_IDENT] = ACL_LOOKUP_PENDING;
return;
} else {
debug(28, 1) ("aclCheck: Can't start ident lookup. No client connection\n");
cbdataUnlock(checklist->conn);
checklist->conn = NULL;
allow = ACCESS_DENIED;
match = -1;
}
}
#endif
else if (checklist->state[ACL_EXTERNAL] == ACL_LOOKUP_NEEDED) {
acl *acl = checklist->current_acl;
assert(acl->type == ACL_EXTERNAL);
externalAclLookup(checklist, acl->data, aclLookupExternalDone, checklist);
return;
}
/*
* We are done with this _acl_access entry. Either the request
* is allowed, denied, requires authentication, or we move on to
* the next entry.
*/
if (match) {
debug(28, 3) ("aclCheck: match found, returning %d\n", allow);
cbdataUnlock(A);
checklist->access_list = NULL;
aclCheckCallback(checklist, allow);
return;
}
checklist->access_list = A->next;
/*
* Lock the next _acl_access entry
*/
if (A->next)
cbdataLock(A->next);
cbdataUnlock(A);
}
debug(28, 3) ("aclCheck: NO match found, returning %d\n", allow !=
ACCESS_DENIED ? ACCESS_DENIED : ACCESS_ALLOWED);
aclCheckCallback(checklist, allow != ACCESS_DENIED ? ACCESS_DENIED :
ACCESS_ALLOWED);
}
void
aclChecklistFree(aclCheck_t * checklist)
{
if (checklist->request)
requestUnlink(checklist->request);
checklist->request = NULL;
if (checklist->conn) {
cbdataUnlock(checklist->conn);
checklist->conn = NULL;
}
if (checklist->access_list) {
cbdataUnlock(checklist->access_list);
checklist->access_list = NULL;
}
if (checklist->callback_data) {
cbdataUnlock(checklist->callback_data);
checklist->callback_data = NULL;
}
aclCheckCleanup(checklist);
cbdataFree(checklist);
}
static void
aclCheckCallback(aclCheck_t * checklist, allow_t answer)
{
debug(28, 3) ("aclCheckCallback: answer=%d\n", answer);
aclCheckCleanup(checklist);
if (cbdataValid(checklist->callback_data))
checklist->callback(answer, checklist->callback_data);
cbdataUnlock(checklist->callback_data);
checklist->callback = NULL;
checklist->callback_data = NULL;
aclChecklistFree(checklist);
}
#if USE_IDENT
static void
aclLookupIdentDone(const char *ident, void *data)
{
aclCheck_t *checklist = data;
if (ident) {
xstrncpy(checklist->rfc931, ident, USER_IDENT_SZ);
#if DONT
xstrncpy(checklist->request->authuser, ident, USER_IDENT_SZ);
#endif
} else {
xstrncpy(checklist->rfc931, dash_str, USER_IDENT_SZ);
}
/*
* Cache the ident result in the connection, to avoid redoing ident lookup
* over and over on persistent connections
*/
if (cbdataValid(checklist->conn) && !checklist->conn->rfc931[0])
xstrncpy(checklist->conn->rfc931, checklist->rfc931, USER_IDENT_SZ);
aclCheck(checklist);
}
#endif
static void
aclLookupDstIPDone(const ipcache_addrs * ia, void *data)
{
aclCheck_t *checklist = data;
checklist->state[ACL_DST_IP] = ACL_LOOKUP_DONE;
aclCheck(checklist);
}
static void
aclLookupDstIPforASNDone(const ipcache_addrs * ia, void *data)
{
aclCheck_t *checklist = data;
checklist->state[ACL_DST_ASN] = ACL_LOOKUP_DONE;
aclCheck(checklist);
}
static void
aclLookupSrcFQDNDone(const char *fqdn, void *data)
{
aclCheck_t *checklist = data;
checklist->state[ACL_SRC_DOMAIN] = ACL_LOOKUP_DONE;
aclCheck(checklist);
}
static void
aclLookupDstFQDNDone(const char *fqdn, void *data)
{
aclCheck_t *checklist = data;
checklist->state[ACL_DST_DOMAIN] = ACL_LOOKUP_DONE;
aclCheck(checklist);
}
static void
aclLookupProxyAuthDone(void *data, char *result)
{
aclCheck_t *checklist = data;
checklist->state[ACL_PROXY_AUTH] = ACL_LOOKUP_DONE;
if (result != NULL)
fatal("AclLookupProxyAuthDone: Old code floating around somewhere.\nMake
clean and if that doesn't work, report a bug to the squid developers.\n");
if (!authenticateValidateUser(checklist->auth_user_request) || checklist->conn == NULL)
{
/* credentials could not be checked either way
* restart the whole process */
/* OR the connection was closed, there's no way to continue */
authenticateAuthUserRequestUnlock(checklist->auth_user_request);
checklist->auth_user_request = NULL;
if (checklist->conn) {
if (checklist->conn->auth_user_request) {
authenticateAuthUserRequestUnlock(checklist->conn->auth_user_request);
checklist->conn->auth_user_request = NULL;
}
checklist->conn->auth_type = AUTH_BROKEN;
}
}
aclCheck(checklist);
}
static void
aclLookupExternalDone(void *data, void *result)
{
aclCheck_t *checklist = data;
checklist->state[ACL_EXTERNAL] = ACL_LOOKUP_DONE;
checklist->extacl_entry = result;
cbdataLock(checklist->extacl_entry);
aclCheck(checklist);
}
aclCheck_t *
aclChecklistCreate(const acl_access * A, request_t * request, const char *ident)
{
int i;
aclCheck_t *checklist;
checklist = cbdataAlloc(aclCheck_t);
checklist->access_list = A;
/*
* aclCheck() makes sure checklist->access_list is a valid
* pointer, so lock it.
*/
cbdataLock(A);
if (request != NULL) {
checklist->request = requestLink(request);
checklist->src_addr = request->client_addr;
checklist->my_addr = request->my_addr;
checklist->my_port = request->my_port;
}
for (i = 0; i < ACL_ENUM_MAX; i++)
checklist->state[i] = ACL_LOOKUP_NONE;
#if USE_IDENT
if (ident)
xstrncpy(checklist->rfc931, ident, USER_IDENT_SZ);
#endif
checklist->auth_user_request = NULL;
return checklist;
}
void
aclNBCheck(aclCheck_t * checklist, PF * callback, void *callback_data)
{
checklist->callback = callback;
checklist->callback_data = callback_data;
cbdataLock(callback_data);
aclCheck(checklist);
}
/*********************/
/* Destroy functions */
/*********************/
static void
aclDestroyTimeList(acl_time_data * data)
{
acl_time_data *next = NULL;
for (; data; data = next) {
next = data->next;
memFree(data, MEM_ACL_TIME_DATA);
}
}
void
aclDestroyRegexList(relist * data)
{
relist *next = NULL;
for (; data; data = next) {
next = data->next;
regfree(&data->regex);
safe_free(data->pattern);
memFree(data, MEM_RELIST);
}
}
static void
aclFreeIpData(void *p)
{
memFree(p, MEM_ACL_IP_DATA);
}
static void
aclFreeUserData(void *data)
{
acl_user_data *d = data;
if (d->names)
splay_destroy(d->names, xfree);
memFree(d, MEM_ACL_USER_DATA);
}
void
aclDestroyAcls(acl ** head)
{
acl *a = NULL;
acl *next = NULL;
for (a = *head; a; a = next) {
next = a->next;
debug(28, 3) ("aclDestroyAcls: '%s'\n", a->cfgline);
switch (a->type) {
case ACL_SRC_IP:
case ACL_DST_IP:
case ACL_MY_IP:
splay_destroy(a->data, aclFreeIpData);
break;
#if USE_ARP_ACL
case ACL_SRC_ARP:
#endif
case ACL_DST_DOMAIN:
case ACL_SRC_DOMAIN:
splay_destroy(a->data, xfree);
break;
#if SQUID_SNMP
case ACL_SNMP_COMMUNITY:
wordlistDestroy((wordlist **) & a->data);
break;
#endif
#if USE_IDENT
case ACL_IDENT:
aclFreeUserData(a->data);
break;
#endif
case ACL_PROXY_AUTH:
aclFreeUserData(a->data);
break;
case ACL_TIME:
aclDestroyTimeList(a->data);
break;
#if USE_IDENT
case ACL_IDENT_REGEX:
#endif
case ACL_PROXY_AUTH_REGEX:
case ACL_URL_REGEX:
case ACL_URLLOGIN:
case ACL_URLPATH_REGEX:
case ACL_BROWSER:
case ACL_REFERER_REGEX:
case ACL_SRC_DOM_REGEX:
case ACL_DST_DOM_REGEX:
case ACL_REP_MIME_TYPE:
case ACL_REQ_MIME_TYPE:
aclDestroyRegexList(a->data);
break;
case ACL_REP_HEADER:
case ACL_REQ_HEADER:
aclDestroyHeader(a->data);
break;
case ACL_PROTO:
case ACL_METHOD:
case ACL_SRC_ASN:
case ACL_DST_ASN:
#if SRC_RTT_NOT_YET_FINISHED
case ACL_NETDB_SRC_RTT:
#endif
case ACL_MAXCONN:
intlistDestroy((intlist **) & a->data);
break;
case ACL_MAX_USER_IP:
aclDestroyUserMaxIP(&a->data);
break;
case ACL_URL_PORT:
case ACL_MY_PORT:
aclDestroyIntRange(a->data);
break;
case ACL_EXTERNAL:
aclDestroyExternal(&a->data);
break;
case ACL_NONE:
case ACL_ENUM_MAX:
debug(28, 1) ("aclDestroyAcls: no case for ACL type %d\n", a->type);
break;
}
safe_free(a->cfgline);
memFree(a, MEM_ACL);
}
*head = NULL;
}
void
aclDestroyAclList(acl_list ** head)
{
acl_list *l;
for (l = *head; l; l = *head) {
*head = l->next;
memFree(l, MEM_ACL_LIST);
}
}
void
aclDestroyAccessList(acl_access ** list)
{
acl_access *l = NULL;
acl_access *next = NULL;
for (l = *list; l; l = next) {
debug(28, 3) ("aclDestroyAccessList: '%s'\n", l->cfgline);
next = l->next;
aclDestroyAclList(&l->acl_list);
safe_free(l->cfgline);
cbdataFree(l);
}
*list = NULL;
}
/* [email protected] (06.09.1996)
*
destroy an _acl_deny_info_list */
void
aclDestroyDenyInfoList(acl_deny_info_list ** list)
{
acl_deny_info_list *a = NULL;
acl_deny_info_list *a_next = NULL;
acl_name_list *l = NULL;
acl_name_list *l_next = NULL;
for (a = *list; a; a = a_next) {
for (l = a->acl_list; l; l = l_next) {
l_next = l->next;
safe_free(l);
}
a_next = a->next;
xfree(a->err_page_name);
memFree(a, MEM_ACL_DENY_INFO_LIST);
}
*list = NULL;
}
static void
aclDestroyIntRange(intrange * list)
{
intrange *w = NULL;
intrange *n = NULL;
for (w = list; w; w = n) {
n = w->next;
safe_free(w);
}
}
/* general compare functions, these are used for tree search algorithms
* so they return <0, 0 or >0 */
/* compare two domains */
static int
aclDomainCompare(const void *a, const void *b)
{
const char *d1;
const char *d2;
int ret;
d1 = b;
d2 = a;
ret = aclHostDomainCompare(d1, d2);
if (ret != 0) {
d1 = a;
d2 = b;
ret = aclHostDomainCompare(d1, d2);
}
if (ret == 0) {
debug(28, 0) ("WARNING: '%s' is a subdomain of '%s'\n", d1, d2);
debug(28, 0) ("WARNING: because of this '%s' is ignored to keep splay tree
searching predictable\n", (char *) a);
debug(28, 0) ("WARNING: You should probably remove '%s' from the ACL named
'%s'\n", d1, AclMatchedName);
}
return ret;
}
/* compare a host and a domain */
static int
aclHostDomainCompare(const void *a, const void *b)
{
const char *h = a;
const char *d = b;
return matchDomainName(h, d);
}
/*
* aclIpDataToStr - print/format an acl_ip_data structure for
* debugging output.
*/
static void
aclIpDataToStr(const acl_ip_data * ip, char *buf, int len)
{
char b1[20];
char b2[20];
char b3[20];
snprintf(b1, 20, "%s", inet_ntoa(ip->addr1));
if (ip->addr2.s_addr != any_addr.s_addr)
snprintf(b2, 20, "-%s", inet_ntoa(ip->addr2));
else
b2[0] = '\0';
if (ip->mask.s_addr != no_addr.s_addr)
snprintf(b3, 20, "/%s", inet_ntoa(ip->mask));
else
b3[0] = '\0';
snprintf(buf, len, "%s%s%s", b1, b2, b3);
}
/*
* aclIpNetworkCompare2 - The guts of the comparison for IP ACLs.
* The first argument (a) is a "host" address, i.e. the IP address
* of a cache client. The second argument (b) is a "network" address
* that might have a subnet and/or range. We mask the host address
* bits with the network subnet mask.
*/
static int
aclIpNetworkCompare2(const acl_ip_data * p, const acl_ip_data * q)
{
struct in_addr A = p->addr1;
const struct in_addr B = q->addr1;
const struct in_addr C = q->addr2;
int rc = 0;
A.s_addr &= q->mask.s_addr; /* apply netmask */
if (C.s_addr == 0) {
/* single address check */
if (ntohl(A.s_addr) > ntohl(B.s_addr))
rc = 1;
else if (ntohl(A.s_addr) < ntohl(B.s_addr))
rc = -1;
else
rc = 0;
} else {
/* range address check */
if (ntohl(A.s_addr) > ntohl(C.s_addr))
rc = 1;
else if (ntohl(A.s_addr) < ntohl(B.s_addr))
rc = -1;
else
rc = 0;
}
return rc;
}
/*
* aclIpNetworkCompare - Compare two acl_ip_data entries. Strictly
* used by the splay insertion routine. It emits a warning if it
* detects a "collision" or overlap that would confuse the splay
* sorting algorithm. Much like aclDomainCompare.
*/
static int
aclIpNetworkCompare(const void *a, const void *b)
{
const acl_ip_data *n1;
const acl_ip_data *n2;
int ret;
n1 = b;
n2 = a;
ret = aclIpNetworkCompare2(n1, n2);
if (ret != 0) {
n1 = a;
n2 = b;
ret = aclIpNetworkCompare2(n1, n2);
}
if (ret == 0) {
char buf_n1[60];
char buf_n2[60];
char buf_a[60];
aclIpDataToStr(n1, buf_n1, 60);
aclIpDataToStr(n2, buf_n2, 60);
aclIpDataToStr((acl_ip_data *) a, buf_a, 60);
debug(28, 0) ("WARNING: '%s' is a subnetwork of "
"'%s'\n", buf_n1, buf_n2);
debug(28, 0) ("WARNING: because of this '%s' is ignored "
"to keep splay tree searching predictable\n", buf_a);
debug(28, 0) ("WARNING: You should probably remove '%s' "
"from the ACL named '%s'\n", buf_n1, AclMatchedName);
}
return ret;
}
/*
* aclIpAddrNetworkCompare - The comparison function used for ACL
* matching checks. The first argument (a) is a "host" address,
* i.e. the IP address of a cache client. The second argument (b)
* is an entry in some address-based access control element. This
* function is called via aclMatchIp() and the splay library.
*/
static int
aclIpAddrNetworkCompare(const void *a, const void *b)
{
return aclIpNetworkCompare2(a, b);
}
static void
aclDumpUserListWalkee(void *node_data, void *outlist)
{
/* outlist is really a wordlist ** */
wordlistAdd(outlist, node_data);
}
static wordlist *
aclDumpUserList(acl_user_data * data)
{
wordlist *wl = NULL;
if (data->flags.case_insensitive)
wordlistAdd(&wl, "-i");
/* damn this is VERY inefficient for long ACL lists... filling
* a wordlist this way costs Sum(1,N) iterations. For instance
* a 1000-elements list will be filled in 499500 iterations.
*/
if (data->flags.required)
wordlistAdd(&wl, "REQUIRED");
else if (data->names)
splay_walk(data->names, aclDumpUserListWalkee, &wl);
return wl;
}
static void
aclDumpIpListWalkee(void *node, void *state)
{
acl_ip_data *ip = node;
MemBuf mb;
wordlist **W = state;
memBufDefInit(&mb);
memBufPrintf(&mb, "%s", inet_ntoa(ip->addr1));
if (ip->addr2.s_addr != any_addr.s_addr)
memBufPrintf(&mb, "-%s", inet_ntoa(ip->addr2));
if (ip->mask.s_addr != no_addr.s_addr)
memBufPrintf(&mb, "/%s", inet_ntoa(ip->mask));
wordlistAdd(W, mb.buf);
memBufClean(&mb);
}
static wordlist *
aclDumpIpList(void *data)
{
wordlist *w = NULL;
splay_walk(data, aclDumpIpListWalkee, &w);
return w;
}
static void
aclDumpDomainListWalkee(void *node, void *state)
{
char *domain = node;
wordlistAdd(state, domain);
}
static wordlist *
aclDumpDomainList(void *data)
{
wordlist *w = NULL;
splay_walk(data, aclDumpDomainListWalkee, &w);
return w;
}
static wordlist *
aclDumpTimeSpecList(acl_time_data * t)
{
wordlist *W = NULL;
char buf[128];
while (t != NULL) {
snprintf(buf, sizeof(buf), "%c%c%c%c%c%c%c %02d:%02d-%02d:%02d",
t->weekbits & ACL_SUNDAY ? 'S' : '-',
t->weekbits & ACL_MONDAY ? 'M' : '-',
t->weekbits & ACL_TUESDAY ? 'T' : '-',
t->weekbits & ACL_WEDNESDAY ? 'W' : '-',
t->weekbits & ACL_THURSDAY ? 'H' : '-',
t->weekbits & ACL_FRIDAY ? 'F' : '-',
t->weekbits & ACL_SATURDAY ? 'A' : '-',
t->start / 60, t->start % 60, t->stop / 60, t->stop % 60);
wordlistAdd(&W, buf);
t = t->next;
}
return W;
}
static wordlist *
aclDumpRegexList(relist * data)
{
wordlist *W = NULL;
while (data != NULL) {
wordlistAdd(&W, data->pattern);
data = data->next;
}
return W;
}
static wordlist *
aclDumpIntlistList(intlist * data)
{
wordlist *W = NULL;
char buf[32];
while (data != NULL) {
snprintf(buf, sizeof(buf), "%d", data->i);
wordlistAdd(&W, buf);
data = data->next;
}
return W;
}
static wordlist *
aclDumpIntRangeList(intrange * data)
{
wordlist *W = NULL;
char buf[32];
while (data != NULL) {
if (data->i == data->j)
snprintf(buf, sizeof(buf), "%d", data->i);
else
snprintf(buf, sizeof(buf), "%d-%d", data->i, data->j);
wordlistAdd(&W, buf);
data = data->next;
}
return W;
}
static wordlist *
aclDumpProtoList(intlist * data)
{
wordlist *W = NULL;
while (data != NULL) {
wordlistAdd(&W, ProtocolStr[data->i]);
data = data->next;
}
return W;
}
static wordlist *
aclDumpMethodList(intlist * data)
{
wordlist *W = NULL;
while (data != NULL) {
wordlistAdd(&W, RequestMethodStr[data->i]);
data = data->next;
}
return W;
}
wordlist *
aclDumpGeneric(const acl * a)
{
debug(28, 3) ("aclDumpGeneric: %s type %d\n", a->name, a->type);
switch (a->type) {
case ACL_SRC_IP:
case ACL_DST_IP:
case ACL_MY_IP:
return aclDumpIpList(a->data);
case ACL_SRC_DOMAIN:
case ACL_DST_DOMAIN:
return aclDumpDomainList(a->data);
#if SQUID_SNMP
case ACL_SNMP_COMMUNITY:
return wordlistDup(a->data);
#endif
#if USE_IDENT
case ACL_IDENT:
return aclDumpUserList(a->data);
case ACL_IDENT_REGEX:
return aclDumpRegexList(a->data);
#endif
case ACL_PROXY_AUTH:
return aclDumpUserList(a->data);
case ACL_TIME:
return aclDumpTimeSpecList(a->data);
case ACL_PROXY_AUTH_REGEX:
case ACL_URL_REGEX:
case ACL_URLLOGIN:
case ACL_URLPATH_REGEX:
case ACL_BROWSER:
case ACL_REFERER_REGEX:
case ACL_SRC_DOM_REGEX:
case ACL_DST_DOM_REGEX:
case ACL_REQ_MIME_TYPE:
case ACL_REP_MIME_TYPE:
return aclDumpRegexList(a->data);
case ACL_REQ_HEADER:
case ACL_REP_HEADER:
return aclDumpHeader(a->data);
case ACL_SRC_ASN:
case ACL_MAXCONN:
case ACL_DST_ASN:
return aclDumpIntlistList(a->data);
case ACL_MAX_USER_IP:
return aclDumpUserMaxIP(a->data);
case ACL_URL_PORT:
case ACL_MY_PORT:
return aclDumpIntRangeList(a->data);
case ACL_PROTO:
return aclDumpProtoList(a->data);
case ACL_METHOD:
return aclDumpMethodList(a->data);
#if USE_ARP_ACL
case ACL_SRC_ARP:
return aclDumpArpList(a->data);
#endif
case ACL_EXTERNAL:
return aclDumpExternal(a->data);
case ACL_NONE:
case ACL_ENUM_MAX:
break;
}
debug(28, 1) ("aclDumpGeneric: no case for ACL type %d\n", a->type);
return NULL;
}
/*
* This function traverses all ACL elements referenced
* by an access list (presumably 'http_access'). If
* it finds a PURGE method ACL, then it returns TRUE,
* otherwise FALSE.
*/
int
aclPurgeMethodInUse(acl_access * a)
{
acl_list *b;
for (; a; a = a->next) {
for (b = a->acl_list; b; b = b->next) {
if (ACL_METHOD != b->acl->type)
continue;
if (aclMatchInteger(b->acl->data, METHOD_PURGE))
return 1;
}
}
return 0;
}
#if USE_ARP_ACL
/*
====
BEGIN
ARP
============================================= */
ACL
SUPPORT
/*
* From:
* To:
[email protected] (Dale)
[email protected]
* Subject: Another Squid patch... :)
* Date:
Thu, 04 Dec 1997 19:55:01 +0300
*
====================================================================
========
*
* Working on setting up a proper firewall for a network containing some
* Win'95 computers at our Univ, I've discovered that some smart students
* avoid the restrictions easily just changing their IP addresses in Win'95
* Contol Panel... It has been getting boring, so I took Squid-1.1.18
* sources and added a new acl type for hard-wired access control:
*
* acl <name> arp <Ethernet address> ...
*
* For example,
*
* acl students arp 00:00:21:55:ed:22 00:00:21:ff:55:38
*
* NOTE: Linux code by David Luyer <[email protected]>.
*
Original (BSD-specific) code no longer works.
*
Solaris code by R. Gancarz <[email protected]>
*/
#ifdef _SQUID_SOLARIS_
#include <sys/sockio.h>
#else
#include <sys/sysctl.h>
#endif
#ifdef _SQUID_LINUX_
#include <net/if_arp.h>
#include <sys/ioctl.h>
#else
#include <net/if_dl.h>
#include <net/route.h>
#endif
#include <net/if.h>
#ifdef _SQUID_FREEBSD__
#include <net/if_arp.h>
#endif
#if HAVE_NETINET_IF_ETHER_H
#include <netinet/if_ether.h>
#endif
/*
* Decode an ascii representation (asc) of an ethernet adress, and place
* it in eth[6].
*/
static int
decode_eth(const char *asc, char *eth)
{
int a1 = 0, a2 = 0, a3 = 0, a4 = 0, a5 = 0, a6 = 0;
if (sscanf(asc, "%x:%x:%x:%x:%x:%x", &a1, &a2, &a3, &a4, &a5, &a6) != 6) {
debug(28, 0) ("decode_eth: Invalid ethernet address '%s'\n", asc);
return 0;
/* This is not valid address */
}
eth[0] = (u_char) a1;
eth[1] = (u_char) a2;
eth[2] = (u_char) a3;
eth[3] = (u_char) a4;
eth[4] = (u_char) a5;
eth[5] = (u_char) a6;
return 1;
}
static acl_arp_data *
aclParseArpData(const char *t)
{
LOCAL_ARRAY(char, eth, 256);
acl_arp_data *q = xcalloc(1, sizeof(acl_arp_data));
debug(28, 5) ("aclParseArpData: %s\n", t);
if (sscanf(t, "%[0-9a-fA-F:]", eth) != 1) {
debug(28, 0) ("aclParseArpData: Bad ethernet address: '%s'\n", t);
safe_free(q);
return NULL;
}
if (!decode_eth(eth, q->eth)) {
debug(28, 0) ("%s line %d: %s\n",
cfg_filename, config_lineno, config_input_line);
debug(28, 0) ("aclParseArpData: Ignoring invalid ARP acl entry: can't parse '%s'\n",
eth);
safe_free(q);
return NULL;
}
return q;
}
/*******************/
/* aclParseArpList */
/*******************/
static void
aclParseArpList(void *curlist)
{
char *t = NULL;
splayNode **Top = curlist;
acl_arp_data *q = NULL;
while ((t = strtokFile())) {
if ((q = aclParseArpData(t)) == NULL)
continue;
*Top = splay_insert(q, *Top, aclArpCompare);
}
}
/***************/
/* aclMatchArp */
/***************/
static int
aclMatchArp(void *dataptr, struct in_addr c)
{
#if defined(_SQUID_LINUX_)
struct arpreq arpReq;
struct sockaddr_in ipAddr;
unsigned char ifbuffer[sizeof(struct ifreq) * 64];
struct ifconf ifc;
struct ifreq *ifr;
int offset;
splayNode **Top = dataptr;
/*
* The linux kernel 2.2 maintains per interface ARP caches and
* thus requires an interface name when doing ARP queries.
*
* The older 2.0 kernels appear to use a unified ARP cache,
* and require an empty interface name
*
* To support both, we attempt the lookup with a blank interface
* name first. If that does not succeed, the try each interface
* in turn
*/
/*
* Set up structures for ARP lookup with blank interface name
*/
ipAddr.sin_family = AF_INET;
ipAddr.sin_port = 0;
ipAddr.sin_addr = c;
memset(&arpReq, '\0', sizeof(arpReq));
xmemcpy(&arpReq.arp_pa, &ipAddr, sizeof(struct sockaddr_in));
/* Query ARP table */
if (ioctl(HttpSockets[0], SIOCGARP, &arpReq) != -1) {
/* Skip non-ethernet interfaces */
if (arpReq.arp_ha.sa_family != ARPHRD_ETHER) {
return 0;
}
debug(28, 4) ("Got address %02x:%02x:%02x:%02x:%02x:%02x\n",
arpReq.arp_ha.sa_data[0] & 0xff, arpReq.arp_ha.sa_data[1] & 0xff,
arpReq.arp_ha.sa_data[2] & 0xff, arpReq.arp_ha.sa_data[3] & 0xff,
arpReq.arp_ha.sa_data[4] & 0xff, arpReq.arp_ha.sa_data[5] & 0xff);
/* Do lookup */
*Top = splay_splay(&arpReq.arp_ha.sa_data, *Top, aclArpCompare);
debug(28, 3) ("aclMatchArp: '%s' %s\n",
inet_ntoa(c), splayLastResult ? "NOT found" : "found");
return (0 == splayLastResult);
}
/* lookup list of interface names */
ifc.ifc_len = sizeof(ifbuffer);
ifc.ifc_buf = ifbuffer;
if (ioctl(HttpSockets[0], SIOCGIFCONF, &ifc) < 0) {
debug(28, 1) ("Attempt to retrieve interface list failed: %s\n",
xstrerror());
return 0;
}
if (ifc.ifc_len > sizeof(ifbuffer)) {
debug(28, 1) ("Interface list too long - %d\n", ifc.ifc_len);
return 0;
}
/* Attempt ARP lookup on each interface */
offset = 0;
while (offset < ifc.ifc_len) {
ifr = (struct ifreq *) (ifbuffer + offset);
offset += sizeof(*ifr);
/* Skip loopback and aliased interfaces */
if (0 == strncmp(ifr->ifr_name, "lo", 2))
continue;
if (NULL != strchr(ifr->ifr_name, ':'))
continue;
debug(28, 4) ("Looking up ARP address for %s on %s\n", inet_ntoa(c),
ifr->ifr_name);
/* Set up structures for ARP lookup */
ipAddr.sin_family = AF_INET;
ipAddr.sin_port = 0;
ipAddr.sin_addr = c;
memset(&arpReq, '\0', sizeof(arpReq));
xmemcpy(&arpReq.arp_pa, &ipAddr, sizeof(struct sockaddr_in));
strncpy(arpReq.arp_dev, ifr->ifr_name, sizeof(arpReq.arp_dev) - 1);
arpReq.arp_dev[sizeof(arpReq.arp_dev) - 1] = '\0';
/* Query ARP table */
if (-1 == ioctl(HttpSockets[0], SIOCGARP, &arpReq)) {
/*
* Query failed. Do not log failed lookups or "device
* not supported"
*/
if (ENXIO == errno)
(void) 0;
else if (ENODEV == errno)
(void) 0;
else
debug(28, 1) ("ARP query failed: %s: %s\n",
ifr->ifr_name, xstrerror());
continue;
}
/* Skip non-ethernet interfaces */
if (arpReq.arp_ha.sa_family != ARPHRD_ETHER)
continue;
debug(28, 4) ("Got address %02x:%02x:%02x:%02x:%02x:%02x on %s\n",
arpReq.arp_ha.sa_data[0] & 0xff,
arpReq.arp_ha.sa_data[1] & 0xff,
arpReq.arp_ha.sa_data[2] & 0xff,
arpReq.arp_ha.sa_data[3] & 0xff,
arpReq.arp_ha.sa_data[4] & 0xff,
arpReq.arp_ha.sa_data[5] & 0xff, ifr->ifr_name);
/* Do lookup */
*Top = splay_splay(&arpReq.arp_ha.sa_data, *Top, aclArpCompare);
/* Return if match, otherwise continue to other interfaces */
if (0 == splayLastResult) {
debug(28, 3) ("aclMatchArp: %s found on %s\n",
inet_ntoa(c), ifr->ifr_name);
return 1;
}
/*
* Should we stop looking here? Can the same IP address
* exist on multiple interfaces?
*/
}
#elif defined(_SQUID_SOLARIS_)
struct arpreq arpReq;
struct sockaddr_in ipAddr;
unsigned char ifbuffer[sizeof(struct ifreq) * 64];
struct ifconf ifc;
struct ifreq *ifr;
int offset;
splayNode **Top = dataptr;
/*
* Set up structures for ARP lookup with blank interface name
*/
ipAddr.sin_family = AF_INET;
ipAddr.sin_port = 0;
ipAddr.sin_addr = c;
memset(&arpReq, '\0', sizeof(arpReq));
xmemcpy(&arpReq.arp_pa, &ipAddr, sizeof(struct sockaddr_in));
/* Query ARP table */
if (ioctl(HttpSockets[0], SIOCGARP, &arpReq) != -1) {
/*
* Solaris (at least 2.6/x86) does not use arp_ha.sa_family * it returns 00:00:00:00:00:00 for non-ethernet media
*/
if (arpReq.arp_ha.sa_data[0] == 0 &&
arpReq.arp_ha.sa_data[1] == 0 &&
arpReq.arp_ha.sa_data[2] == 0 &&
arpReq.arp_ha.sa_data[3] == 0 &&
arpReq.arp_ha.sa_data[4] == 0 && arpReq.arp_ha.sa_data[5] == 0)
return 0;
debug(28, 4) ("Got address %02x:%02x:%02x:%02x:%02x:%02x\n",
arpReq.arp_ha.sa_data[0] & 0xff, arpReq.arp_ha.sa_data[1] & 0xff,
arpReq.arp_ha.sa_data[2] & 0xff, arpReq.arp_ha.sa_data[3] & 0xff,
arpReq.arp_ha.sa_data[4] & 0xff, arpReq.arp_ha.sa_data[5] & 0xff);
/* Do lookup */
*Top = splay_splay(&arpReq.arp_ha.sa_data, *Top, aclArpCompare);
debug(28, 3) ("aclMatchArp: '%s' %s\n",
inet_ntoa(c), splayLastResult ? "NOT found" : "found");
return (0 == splayLastResult);
}
#elif defined(_SQUID_FREEBSD_)
struct arpreq arpReq;
struct sockaddr_in ipAddr;
unsigned char ifbuffer[sizeof(struct ifreq) * 64];
struct ifconf ifc;
struct ifreq *ifr;
int offset;
splayNode **Top = dataptr;
int mib[6];
size_t needed;
char *lim, *buf, *next;
struct rt_msghdr *rtm;
struct sockaddr_inarp *sin;
struct sockaddr_dl *sdl;
/*
* Set up structures for ARP lookup with blank interface name
*/
ipAddr.sin_family = AF_INET;
ipAddr.sin_port = 0;
ipAddr.sin_addr = c;
memset(&arpReq, '\0', sizeof(arpReq));
xmemcpy(&arpReq.arp_pa, &ipAddr, sizeof(struct sockaddr_in));
/* Query ARP table */
mib[0] = CTL_NET;
mib[1] = PF_ROUTE;
mib[2] = 0;
mib[3] = AF_INET;
mib[4] = NET_RT_FLAGS;
mib[5] = RTF_LLINFO;
if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) {
debug(28, 0) ("Can't estimate ARP table size!\n");
return 0;
}
if ((buf = xmalloc(needed)) == NULL) {
debug(28, 0) ("Can't allocate temporary ARP table!\n");
return 0;
}
if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0) {
debug(28, 0) ("Can't retrieve ARP table!\n");
xfree(buf);
return 0;
}
lim = buf + needed;
for (next = buf; next < lim; next += rtm->rtm_msglen) {
rtm = (struct rt_msghdr *) next;
sin = (struct sockaddr_inarp *) (rtm + 1);
/*sdl = (struct sockaddr_dl *) (sin + 1); */
#define ROUNDUP(a) \
((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
(char *) sdl = (char *) sin + ROUNDUP(sin->sin_len);
if (c.s_addr == sin->sin_addr.s_addr) {
if (sdl->sdl_alen) {
arpReq.arp_ha.sa_len = sizeof(struct sockaddr);
arpReq.arp_ha.sa_family = AF_UNSPEC;
memcpy(arpReq.arp_ha.sa_data, LLADDR(sdl), sdl->sdl_alen);
}
}
}
xfree(buf);
if (arpReq.arp_ha.sa_data[0] == 0 && arpReq.arp_ha.sa_data[1] == 0 &&
arpReq.arp_ha.sa_data[2] == 0 && arpReq.arp_ha.sa_data[3] == 0 &&
arpReq.arp_ha.sa_data[4] == 0 && arpReq.arp_ha.sa_data[5] == 0)
return 0;
debug(28, 4) ("Got address %02x:%02x:%02x:%02x:%02x:%02x\n",
arpReq.arp_ha.sa_data[0] & 0xff, arpReq.arp_ha.sa_data[1] & 0xff,
arpReq.arp_ha.sa_data[2] & 0xff, arpReq.arp_ha.sa_data[3] & 0xff,
arpReq.arp_ha.sa_data[4] & 0xff, arpReq.arp_ha.sa_data[5] & 0xff);
/* Do lookup */
*Top = splay_splay(&arpReq.arp_ha.sa_data, *Top, aclArpCompare);
debug(28, 3) ("aclMatchArp: '%s' %s\n",
inet_ntoa(c), splayLastResult ? "NOT found" : "found");
return (0 == splayLastResult);
#else
WRITE ME;
#endif
/*
* Address was not found on any interface
*/
debug(28, 3) ("aclMatchArp: %s NOT found\n", inet_ntoa(c));
return 0;
}
static int
aclArpCompare(const void *a, const void *b)
{
#if defined(_SQUID_LINUX_)
const unsigned short *d1 = a;
const unsigned short *d2 = b;
if (d1[0] != d2[0])
return (d1[0] > d2[0]) ? 1 : -1;
if (d1[1] != d2[1])
return (d1[1] > d2[1]) ? 1 : -1;
if (d1[2] != d2[2])
return (d1[2] > d2[2]) ? 1 : -1;
#elif defined(_SQUID_SOLARIS_)
const unsigned char *d1 = a;
const unsigned char *d2 = b;
if (d1[0] != d2[0])
return (d1[0] > d2[0]) ? 1 : -1;
if (d1[1] != d2[1])
return (d1[1] > d2[1]) ? 1 : -1;
if (d1[2] != d2[2])
return (d1[2] > d2[2]) ? 1 : -1;
if (d1[3] != d2[3])
return (d1[3] > d2[3]) ? 1 : -1;
if (d1[4] != d2[4])
return (d1[4] > d2[4]) ? 1 : -1;
if (d1[5] != d2[5])
return (d1[5] > d2[5]) ? 1 : -1;
#elif defined(_SQUID_FREEBSD_)
const unsigned char *d1 = a;
const unsigned char *d2 = b;
if (d1[0] != d2[0])
return (d1[0] > d2[0]) ? 1 : -1;
if (d1[1] != d2[1])
return (d1[1] > d2[1]) ? 1 : -1;
if (d1[2] != d2[2])
return (d1[2] > d2[2]) ? 1 : -1;
if (d1[3] != d2[3])
return (d1[3] > d2[3]) ? 1 : -1;
if (d1[4] != d2[4])
return (d1[4] > d2[4]) ? 1 : -1;
if (d1[5] != d2[5])
return (d1[5] > d2[5]) ? 1 : -1;
#else
WRITE ME;
#endif
return 0;
}
#if UNUSED_CODE
/**********************************************************************
* This is from the pre-splay-tree code for BSD
* I suspect the Linux approach will work on most O/S and be much
* better - <[email protected]>
***********************************************************************
static int
checkARP(u_long ip, char *eth)
{
int mib[6] =
{CTL_NET, PF_ROUTE, 0, AF_INET, NET_RT_FLAGS, RTF_LLINFO};
size_t needed;
char *buf, *next, *lim;
struct rt_msghdr *rtm;
struct sockaddr_inarp *sin;
struct sockaddr_dl *sdl;
if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) {
debug(28, 0) ("Can't estimate ARP table size!\n");
return 0;
}
if ((buf = xmalloc(needed)) == NULL) {
debug(28, 0) ("Can't allocate temporary ARP table!\n");
return 0;
}
if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0) {
debug(28, 0) ("Can't retrieve ARP table!\n");
xfree(buf);
return 0;
}
lim = buf + needed;
for (next = buf; next < lim; next += rtm->rtm_msglen) {
rtm = (struct rt_msghdr *) next;
sin = (struct sockaddr_inarp *) (rtm + 1);
sdl = (struct sockaddr_dl *) (sin + 1);
if (sin->sin_addr.s_addr == ip) {
if (sdl->sdl_alen)
if (!memcmp(LLADDR(sdl), eth, 6)) {
xfree(buf);
return 1;
}
break;
}
}
xfree(buf);
return 0;
}
**********************************************************************/
#endif
static void
aclDumpArpListWalkee(void *node, void *state)
{
acl_arp_data *arp = node;
wordlist **W = state;
static char buf[24];
while (*W != NULL)
W = &(*W)->next;
snprintf(buf, sizeof(buf), "%02x:%02x:%02x:%02x:%02x:%02x",
arp->eth[0], arp->eth[1], arp->eth[2], arp->eth[3],
arp->eth[4], arp->eth[5]);
wordlistAdd(state, buf);
}
static wordlist *
aclDumpArpList(void *data)
{
wordlist *w = NULL;
splay_walk(data, aclDumpArpListWalkee, &w);
return w;
}
/*
====
END
ARP
ACL
=============================================== */
#endif /* USE_ARP_ACL */
SUPPORT
static squid_acl
aclStrToType(const char *s)
{
if (!strcmp(s, "src"))
return ACL_SRC_IP;
if (!strcmp(s, "dst"))
return ACL_DST_IP;
if (!strcmp(s, "myip"))
return ACL_MY_IP;
if (!strcmp(s, "domain"))
return ACL_DST_DOMAIN;
if (!strcmp(s, "dstdomain"))
return ACL_DST_DOMAIN;
if (!strcmp(s, "srcdomain"))
return ACL_SRC_DOMAIN;
if (!strcmp(s, "dstdom_regex"))
return ACL_DST_DOM_REGEX;
if (!strcmp(s, "srcdom_regex"))
return ACL_SRC_DOM_REGEX;
if (!strcmp(s, "time"))
return ACL_TIME;
if (!strcmp(s, "pattern"))
return ACL_URLPATH_REGEX;
if (!strcmp(s, "urlpath_regex"))
return ACL_URLPATH_REGEX;
if (!strcmp(s, "url_regex")) //Compara a string que foi passada
return ACL_URL_REGEX;
// como parametro.
if (!strcmp(s, "port"))
return ACL_URL_PORT;
if (!strcmp(s, "myport"))
return ACL_MY_PORT;
if (!strcmp(s, "maxconn"))
return ACL_MAXCONN;
#if USE_IDENT
if (!strcmp(s, "ident"))
return ACL_IDENT;
if (!strcmp(s, "ident_regex"))
return ACL_IDENT_REGEX;
#endif
if (!strncmp(s, "proto", 5))
return ACL_PROTO;
if (!strcmp(s, "method"))
return ACL_METHOD;
if (!strcmp(s, "browser"))
return ACL_BROWSER;
if (!strcmp(s, "referer_regex"))
return ACL_REFERER_REGEX;
if (!strcmp(s, "proxy_auth"))
return ACL_PROXY_AUTH;
if (!strcmp(s, "proxy_auth_regex"))
return ACL_PROXY_AUTH_REGEX;
if (!strcmp(s, "src_as"))
return ACL_SRC_ASN;
if (!strcmp(s, "dst_as"))
return ACL_DST_ASN;
#if SQUID_SNMP
if (!strcmp(s, "snmp_community"))
return ACL_SNMP_COMMUNITY;
#endif
#if SRC_RTT_NOT_YET_FINISHED
if (!strcmp(s, "src_rtt"))
return ACL_NETDB_SRC_RTT;
#endif
#if USE_ARP_ACL
if (!strcmp(s, "arp"))
return ACL_SRC_ARP;
#endif
if (!strcmp(s, "req_mime_type"))
return ACL_REQ_MIME_TYPE;
}
if (!strcmp(s, "rep_mime_type"))
return ACL_REP_MIME_TYPE;
if (!strcmp(s, "rep_header"))
return ACL_REP_HEADER;
if (!strcmp(s, "req_header"))
return ACL_REQ_HEADER;
if (!strcmp(s, "max_user_ip"))
return ACL_MAX_USER_IP;
if (!strcmp(s, "external"))
return ACL_EXTERNAL;
if (!strcmp(s, "urllogin"))
return ACL_URLLOGIN;
return ACL_NONE;
const char *
aclTypeToStr(squid_acl type)
{
if (type == ACL_SRC_IP)
return "src";
if (type == ACL_DST_IP)
return "dst";
if (type == ACL_MY_IP)
return "myip";
if (type == ACL_DST_DOMAIN)
return "dstdomain";
if (type == ACL_SRC_DOMAIN)
return "srcdomain";
if (type == ACL_DST_DOM_REGEX)
return "dstdom_regex";
if (type == ACL_SRC_DOM_REGEX)
return "srcdom_regex";
if (type == ACL_TIME)
return "time";
if (type == ACL_URLPATH_REGEX)
return "urlpath_regex";
if (type == ACL_URL_REGEX)
return "url_regex";
if (type == ACL_URL_PORT)
return "port";
if (type == ACL_MY_PORT)
return "myport";
if (type == ACL_MAXCONN)
return "maxconn";
#if USE_IDENT
if (type == ACL_IDENT)
return "ident";
if (type == ACL_IDENT_REGEX)
return "ident_regex";
#endif
if (type == ACL_PROTO)
return "proto";
if (type == ACL_METHOD)
return "method";
if (type == ACL_BROWSER)
return "browser";
if (type == ACL_REFERER_REGEX)
return
if (type
return
if (type
"referer_regex";
== ACL_PROXY_AUTH)
"proxy_auth";
== ACL_PROXY_AUTH_REGEX)
return "proxy_auth_regex";
if (type == ACL_SRC_ASN)
return "src_as";
if (type == ACL_DST_ASN)
return "dst_as";
#if SQUID_SNMP
if (type == ACL_SNMP_COMMUNITY)
return "snmp_community";
#endif
#if SRC_RTT_NOT_YET_FINISHED
if (type == ACL_NETDB_SRC_RTT)
return "src_rtt";
#endif
#if USE_ARP_ACL
if (type == ACL_SRC_ARP)
return "arp";
#endif
if (type == ACL_REQ_MIME_TYPE)
return "req_mime_type";
if (type == ACL_REP_MIME_TYPE)
return "rep_mime_type";
if (type == ACL_REP_HEADER)
return "rep_header";
if (type == ACL_REQ_HEADER)
return "req_header";
if (type == ACL_MAX_USER_IP)
return "max_user_ip";
if (type == ACL_EXTERNAL)
return "external";
if (type == ACL_URLLOGIN)
return "urllogin";
return "ERROR";
}
void
aclParseAclLine(acl ** head)
{
/* we're already using strtok() to grok the line */
char *t = NULL;
acl *A = NULL;
LOCAL_ARRAY(char, aclname, ACL_NAME_SZ);
squid_acl acltype;
int new_acl = 0;
/* snarf the ACL name */
if ((t = strtok(NULL, w_space)) == NULL) {
debug(28, 0) ("%s line %d: %s\n",
cfg_filename, config_lineno, config_input_line);
debug(28, 0) ("aclParseAclLine: missing ACL name.\n");
return;
}
xstrncpy(aclname, t, ACL_NAME_SZ);
/* snarf the ACL type */
if ((t = strtok(NULL, w_space)) == NULL) {
debug(28, 0) ("%s line %d: %s\n",
cfg_filename, config_lineno, config_input_line);
debug(28, 0) ("aclParseAclLine: missing ACL type.\n");
return;
}
if ((acltype = aclStrToType(t)) == ACL_NONE) {
debug(28, 0) ("%s line %d: %s\n",
cfg_filename, config_lineno, config_input_line);
debug(28, 0) ("aclParseAclLine: Invalid ACL type '%s'\n", t);
return;
}
if ((A = aclFindByName(aclname)) == NULL) {
debug(28, 3) ("aclParseAclLine: Creating ACL '%s'\n", aclname);
A = memAllocate(MEM_ACL);
xstrncpy(A->name, aclname, ACL_NAME_SZ);
A->type = acltype;
A->cfgline = xstrdup(config_input_line);
new_acl = 1;
} else {
if (acltype != A->type) {
debug(28, 0) ("aclParseAclLine: ACL '%s' already exists with different
type, skipping.\n", A->name);
return;
}
debug(28, 3) ("aclParseAclLine: Appending to '%s'\n", aclname);
new_acl = 0;
}
/*
* Here we set AclMatchedName in case we need to use it in a
* warning message in aclDomainCompare().
*/
AclMatchedName = aclname; /* ugly */
switch (A->type) {
case ACL_SRC_IP:
case ACL_DST_IP:
case ACL_MY_IP:
aclParseIpList(&A->data);
break;
case ACL_SRC_DOMAIN:
case ACL_DST_DOMAIN:
aclParseDomainList(&A->data);
break;
case ACL_TIME:
aclParseTimeSpec(&A->data);
break;
case ACL_URL_REGEX:
case ACL_URLLOGIN:
case ACL_URLPATH_REGEX:
case ACL_BROWSER:
case ACL_REFERER_REGEX:
case ACL_SRC_DOM_REGEX:
case ACL_DST_DOM_REGEX:
case ACL_REQ_MIME_TYPE:
case ACL_REP_MIME_TYPE:
aclParseRegexList(&A->data);
break;
case ACL_REP_HEADER:
case ACL_REQ_HEADER:
aclParseHeader(&A->data);
break;
case ACL_SRC_ASN:
case ACL_MAXCONN:
case ACL_DST_ASN:
aclParseIntlist(&A->data);
break;
case ACL_MAX_USER_IP:
aclParseUserMaxIP(&A->data);
break;
#if SRC_RTT_NOT_YET_FINISHED
case ACL_NETDB_SRC_RTT:
aclParseIntlist(&A->data);
break;
#endif
case ACL_URL_PORT:
case ACL_MY_PORT:
aclParseIntRange(&A->data);
break;
#if USE_IDENT
case ACL_IDENT:
aclParseUserList(&A->data);
break;
case ACL_IDENT_REGEX:
aclParseRegexList(&A->data);
break;
#endif
case ACL_PROTO:
aclParseProtoList(&A->data);
break;
case ACL_METHOD:
aclParseMethodList(&A->data);
break;
case ACL_PROXY_AUTH:
if (authenticateSchemeCount() == 0) {
debug(28, 0) ("aclParseAclLine: IGNORING: Proxy Auth ACL '%s' \
because no authentication schemes were compiled.\n", A->cfgline);
} else if (authenticateActiveSchemeCount() == 0) {
debug(28, 0) ("aclParseAclLine: IGNORING: Proxy Auth ACL '%s' \
because no authentication schemes are fully configured.\n", A->cfgline);
} else {
aclParseUserList(&A->data);
}
break;
case ACL_PROXY_AUTH_REGEX:
if (authenticateSchemeCount() == 0) {
debug(28, 0) ("aclParseAclLine: IGNORING: Proxy Auth ACL '%s' \
because no authentication schemes were compiled.\n", A->cfgline);
} else if (authenticateActiveSchemeCount() == 0) {
debug(28, 0) ("aclParseAclLine: IGNORING: Proxy Auth ACL '%s' \
because no authentication schemes are fully configured.\n", A->cfgline);
} else {
aclParseRegexList(&A->data);
}
break;
#if SQUID_SNMP
case ACL_SNMP_COMMUNITY:
aclParseWordList(&A->data);
break;
#endif
#if USE_ARP_ACL
case ACL_SRC_ARP:
aclParseArpList(&A->data);
break;
#endif
case ACL_EXTERNAL:
aclParseExternal(&A->data);
break;
case ACL_NONE:
case ACL_ENUM_MAX:
fatal("Bad ACL type");
break;
}
/*
}
* Clear AclMatchedName from our temporary hack
*/
AclMatchedName = NULL;
/* ugly */
if (!new_acl)
return;
if (A->data == NULL) {
debug(28, 0) ("aclParseAclLine: IGNORING invalid ACL: %s\n",
A->cfgline);
memFree(A, MEM_ACL);
return;
}
/* append */
while (*head)
head = &(*head)->next;
*head = A;
static int
aclMatchAcl(acl * ae, aclCheck_t * checklist)
{
request_t *r = checklist->request;
const ipcache_addrs *ia = NULL;
const char *fqdn = NULL;
char *esc_buf;
const char *header;
const char *browser;
int k, ti;
if (!ae)
return 0;
switch (ae->type) {
case ACL_BROWSER:
case ACL_REFERER_REGEX:
case ACL_DST_ASN:
case ACL_DST_DOMAIN:
case ACL_DST_DOM_REGEX:
case ACL_DST_IP:
case ACL_MAX_USER_IP:
case ACL_METHOD:
case ACL_PROTO:
case ACL_PROXY_AUTH:
case ACL_PROXY_AUTH_REGEX:
case ACL_REP_MIME_TYPE:
case ACL_REQ_MIME_TYPE:
case ACL_REP_HEADER:
case ACL_REQ_HEADER:
case ACL_URLPATH_REGEX:
case ACL_URL_PORT:
case ACL_URL_REGEX:
case ACL_URLLOGIN:
/* These ACL types require checklist->request */
if (NULL == r) {
debug(28, 1) ("WARNING: '%s' ACL is used but there is no"
" HTTP request -- access denied.\n", ae->name);
return 0;
}
break;
default:
break;
}
debug(28, 3) ("aclMatchAcl: checking '%s'\n", ae->cfgline);
switch (ae->type) {
case ACL_SRC_IP:
return aclMatchIp(&ae->data, checklist->src_addr);
/* NOTREACHED */
case ACL_MY_IP:
return aclMatchIp(&ae->data, checklist->my_addr);
/* NOTREACHED */
case ACL_DST_IP:
ia = ipcache_gethostbyname(r->host, IP_LOOKUP_IF_MISS);
if (ia) {
for (k = 0; k < (int) ia->count; k++) {
if (aclMatchIp(&ae->data, ia->in_addrs[k]))
return 1;
}
return 0;
} else if (checklist->state[ACL_DST_IP] == ACL_LOOKUP_NONE) {
debug(28, 3) ("aclMatchAcl: Can't yet compare '%s' ACL for '%s'\n",
ae->name, r->host);
checklist->state[ACL_DST_IP] = ACL_LOOKUP_NEEDED;
return 0;
} else {
return aclMatchIp(&ae->data, no_addr);
}
/* NOTREACHED */
case ACL_DST_DOMAIN:
if ((ia = ipcacheCheckNumeric(r->host)) == NULL)
return aclMatchDomainList(&ae->data, r->host);
fqdn = fqdncache_gethostbyaddr(ia->in_addrs[0], FQDN_LOOKUP_IF_MISS);
if (fqdn)
return aclMatchDomainList(&ae->data, fqdn);
if (checklist->state[ACL_DST_DOMAIN] == ACL_LOOKUP_NONE) {
debug(28, 3) ("aclMatchAcl: Can't yet compare '%s' ACL for '%s'\n",
ae->name, inet_ntoa(ia->in_addrs[0]));
checklist->state[ACL_DST_DOMAIN] = ACL_LOOKUP_NEEDED;
return 0;
}
return aclMatchDomainList(&ae->data, "none");
/* NOTREACHED */
case ACL_SRC_DOMAIN:
fqdn = fqdncache_gethostbyaddr(checklist->src_addr, FQDN_LOOKUP_IF_MISS);
if (fqdn) {
return aclMatchDomainList(&ae->data, fqdn);
} else if (checklist->state[ACL_SRC_DOMAIN] == ACL_LOOKUP_NONE) {
debug(28, 3) ("aclMatchAcl: Can't yet compare '%s' ACL for '%s'\n",
ae->name, inet_ntoa(checklist->src_addr));
checklist->state[ACL_SRC_DOMAIN] = ACL_LOOKUP_NEEDED;
return 0;
}
return aclMatchDomainList(&ae->data, "none");
/* NOTREACHED */
case ACL_DST_DOM_REGEX:
if ((ia = ipcacheCheckNumeric(r->host)) == NULL)
return aclMatchRegex(ae->data, r->host);
fqdn = fqdncache_gethostbyaddr(ia->in_addrs[0], FQDN_LOOKUP_IF_MISS);
if (fqdn)
return aclMatchRegex(ae->data, fqdn);
if (checklist->state[ACL_DST_DOMAIN] == ACL_LOOKUP_NONE) {
debug(28, 3) ("aclMatchAcl: Can't yet compare '%s' ACL for '%s'\n",
ae->name, inet_ntoa(ia->in_addrs[0]));
checklist->state[ACL_DST_DOMAIN] = ACL_LOOKUP_NEEDED;
return 0;
}
return aclMatchRegex(ae->data, "none");
/* NOTREACHED */
case ACL_SRC_DOM_REGEX:
fqdn = fqdncache_gethostbyaddr(checklist->src_addr, FQDN_LOOKUP_IF_MISS);
if (fqdn) {
return aclMatchRegex(ae->data, fqdn);
} else if (checklist->state[ACL_SRC_DOMAIN] == ACL_LOOKUP_NONE) {
debug(28, 3) ("aclMatchAcl: Can't yet compare '%s' ACL for '%s'\n",
ae->name, inet_ntoa(checklist->src_addr));
checklist->state[ACL_SRC_DOMAIN] = ACL_LOOKUP_NEEDED;
return 0;
}
return aclMatchRegex(ae->data, "none");
/* NOTREACHED */
case ACL_TIME:
return aclMatchTime(ae->data, squid_curtime);
/* NOTREACHED */
case ACL_URLPATH_REGEX:
esc_buf = xstrdup(strBuf(r->urlpath));
rfc1738_unescape(esc_buf);
k = aclMatchRegex(ae->data, esc_buf);
safe_free(esc_buf);
return k;
/* NOTREACHED */
case ACL_URL_REGEX:
esc_buf = xstrdup(urlCanonical(r));
rfc1738_unescape(esc_buf);
k = aclMatchRegex(ae->data, esc_buf);
safe_free(esc_buf);
return k;
case ACL_URLLOGIN:
esc_buf = xstrdup(r->login);
rfc1738_unescape(esc_buf);
k = aclMatchRegex(ae->data, esc_buf);
safe_free(esc_buf);
return k;
/* NOTREACHED */
case ACL_MAXCONN:
k = clientdbEstablished(checklist->src_addr, 0);
return ((k > ((intlist *) ae->data)->i) ? 1 : 0);
/* NOTREACHED */
case ACL_URL_PORT:
return aclMatchIntegerRange(ae->data, (int) r->port);
/* NOTREACHED */
case ACL_MY_PORT:
return aclMatchIntegerRange(ae->data, (int) checklist->my_port);
/* NOTREACHED */
#if USE_IDENT
case ACL_IDENT:
if (checklist->rfc931[0]) {
return aclMatchUser(ae->data, checklist->rfc931);
} else {
checklist->state[ACL_IDENT] = ACL_LOOKUP_NEEDED;
return 0;
}
/* NOTREACHED */
case ACL_IDENT_REGEX:
if (checklist->rfc931[0]) {
return aclMatchRegex(ae->data, checklist->rfc931);
} else {
checklist->state[ACL_IDENT] = ACL_LOOKUP_NEEDED;
return 0;
}
/* NOTREACHED */
#endif
case ACL_PROTO:
return aclMatchInteger(ae->data, r->protocol);
/* NOTREACHED */
case ACL_METHOD:
return aclMatchInteger(ae->data, r->method);
/* NOTREACHED */
case ACL_BROWSER:
browser = httpHeaderGetStr(&checklist->request->header, HDR_USER_AGENT);
if (NULL == browser)
return 0;
return aclMatchRegex(ae->data, browser);
/* NOTREACHED */
case ACL_REFERER_REGEX:
header = httpHeaderGetStr(&checklist->request->header, HDR_REFERER);
if (NULL == header)
return 0;
return aclMatchRegex(ae->data, header);
/* NOTREACHED */
case ACL_PROXY_AUTH:
case ACL_PROXY_AUTH_REGEX:
if ((ti = aclAuthenticated(checklist)) != 1)
return ti;
ti = aclMatchProxyAuth(ae->data, r->auth_user_request,
checklist, ae->type);
return ti;
/* NOTREACHED */
case ACL_MAX_USER_IP:
if ((ti = aclAuthenticated(checklist)) != 1)
return ti;
ti = aclMatchUserMaxIP(ae->data, r->auth_user_request,
checklist->src_addr);
return ti;
/* NOTREACHED */
#if SQUID_SNMP
case ACL_SNMP_COMMUNITY:
return aclMatchWordList(ae->data, checklist->snmp_community);
/* NOTREACHED */
#endif
case ACL_SRC_ASN:
return asnMatchIp(ae->data, checklist->src_addr);
/* NOTREACHED */
case ACL_DST_ASN:
ia = ipcache_gethostbyname(r->host, IP_LOOKUP_IF_MISS);
if (ia) {
for (k = 0; k < (int) ia->count; k++) {
if (asnMatchIp(ae->data, ia->in_addrs[k]))
return 1;
}
return 0;
} else if (checklist->state[ACL_DST_ASN] == ACL_LOOKUP_NONE) {
debug(28, 3) ("asnMatchAcl: Can't yet compare '%s' ACL for '%s'\n",
ae->name, r->host);
checklist->state[ACL_DST_ASN] = ACL_LOOKUP_NEEDED;
} else {
return asnMatchIp(ae->data, no_addr);
}
return 0;
/* NOTREACHED */
#if USE_ARP_ACL
case ACL_SRC_ARP:
return aclMatchArp(&ae->data, checklist->src_addr);
/* NOTREACHED */
#endif
case ACL_REQ_MIME_TYPE:
header = httpHeaderGetStr(&checklist->request->header,
HDR_CONTENT_TYPE);
if (NULL == header)
header = "";
return aclMatchRegex(ae->data, header);
/* NOTREACHED */
case ACL_REP_MIME_TYPE:
if (!checklist->reply)
return 0;
header = httpHeaderGetStr(&checklist->reply->header, HDR_CONTENT_TYPE);
if (NULL == header)
header = "";
return aclMatchRegex(ae->data, header);
/* NOTREACHED */
case ACL_REP_HEADER:
if (!checklist->reply)
return 0;
return aclMatchHeader(ae->data, &checklist->reply->header);
/* NOTREACHED */
case ACL_REQ_HEADER:
return aclMatchHeader(ae->data, &checklist->request->header);
/* NOTREACHED */
case ACL_EXTERNAL:
return aclMatchExternal(ae->data, checklist);
/* NOTREACHED */
case ACL_NONE:
case ACL_ENUM_MAX:
break;
}
debug(28, 0) ("aclMatchAcl: '%s' has bad type %d\n",
ae->name, ae->type);
return 0;
}
void
aclDestroyAcls(acl ** head)
{
acl *a = NULL;
acl *next = NULL;
for (a = *head; a; a = next) {
next = a->next;
debug(28, 3) ("aclDestroyAcls: '%s'\n", a->cfgline);
switch (a->type) {
case ACL_SRC_IP:
case ACL_DST_IP:
case ACL_MY_IP:
splay_destroy(a->data, aclFreeIpData);
break;
#if USE_ARP_ACL
case ACL_SRC_ARP:
#endif
case ACL_DST_DOMAIN:
case ACL_SRC_DOMAIN:
splay_destroy(a->data, xfree);
break;
#if SQUID_SNMP
case ACL_SNMP_COMMUNITY:
wordlistDestroy((wordlist **) & a->data);
break;
#endif
#if USE_IDENT
case ACL_IDENT:
aclFreeUserData(a->data);
break;
#endif
case ACL_PROXY_AUTH:
aclFreeUserData(a->data);
break;
case ACL_TIME:
aclDestroyTimeList(a->data);
break;
#if USE_IDENT
case ACL_IDENT_REGEX:
#endif
case ACL_PROXY_AUTH_REGEX:
case ACL_URL_REGEX:
case ACL_URLLOGIN:
case ACL_URLPATH_REGEX:
case ACL_BROWSER:
case ACL_REFERER_REGEX:
case ACL_SRC_DOM_REGEX:
case ACL_DST_DOM_REGEX:
case ACL_REP_MIME_TYPE:
case ACL_REQ_MIME_TYPE:
aclDestroyRegexList(a->data);
break;
case ACL_REP_HEADER:
case ACL_REQ_HEADER:
aclDestroyHeader(a->data);
break;
case ACL_PROTO:
case ACL_METHOD:
case ACL_SRC_ASN:
case ACL_DST_ASN:
#if SRC_RTT_NOT_YET_FINISHED
case ACL_NETDB_SRC_RTT:
#endif
case ACL_MAXCONN:
intlistDestroy((intlist **) & a->data);
break;
case ACL_MAX_USER_IP:
aclDestroyUserMaxIP(&a->data);
break;
case ACL_URL_PORT:
case ACL_MY_PORT:
aclDestroyIntRange(a->data);
break;
case ACL_EXTERNAL:
aclDestroyExternal(&a->data);
break;
case ACL_NONE:
case ACL_ENUM_MAX:
debug(28, 1) ("aclDestroyAcls: no case for ACL type %d\n", a->type);
break;
}
safe_free(a->cfgline);
memFree(a, MEM_ACL);
}
*head = NULL;
}
wordlist *
aclDumpGeneric(const acl * a)
{
debug(28, 3) ("aclDumpGeneric: %s type %d\n", a->name, a->type);
switch (a->type) {
case ACL_SRC_IP:
case ACL_DST_IP:
case ACL_MY_IP:
return aclDumpIpList(a->data);
case ACL_SRC_DOMAIN:
case ACL_DST_DOMAIN:
return aclDumpDomainList(a->data);
#if SQUID_SNMP
case ACL_SNMP_COMMUNITY:
return wordlistDup(a->data);
#endif
#if USE_IDENT
case ACL_IDENT:
return aclDumpUserList(a->data);
case ACL_IDENT_REGEX:
return aclDumpRegexList(a->data);
#endif
case ACL_PROXY_AUTH:
return aclDumpUserList(a->data);
case ACL_TIME:
return aclDumpTimeSpecList(a->data);
case ACL_PROXY_AUTH_REGEX:
case ACL_URL_REGEX:
case ACL_URLLOGIN:
case ACL_URLPATH_REGEX:
case ACL_BROWSER:
case ACL_REFERER_REGEX:
case ACL_SRC_DOM_REGEX:
case ACL_DST_DOM_REGEX:
case ACL_REQ_MIME_TYPE:
case ACL_REP_MIME_TYPE:
return aclDumpRegexList(a->data);
case ACL_REQ_HEADER:
case ACL_REP_HEADER:
return aclDumpHeader(a->data);
case ACL_SRC_ASN:
case ACL_MAXCONN:
case ACL_DST_ASN:
return aclDumpIntlistList(a->data);
case ACL_MAX_USER_IP:
return aclDumpUserMaxIP(a->data);
case ACL_URL_PORT:
case ACL_MY_PORT:
return aclDumpIntRangeList(a->data);
case ACL_PROTO:
return aclDumpProtoList(a->data);
case ACL_METHOD:
return aclDumpMethodList(a->data);
#if USE_ARP_ACL
case ACL_SRC_ARP:
return aclDumpArpList(a->data);
#endif
case ACL_EXTERNAL:
return aclDumpExternal(a->data);
case ACL_NONE:
case ACL_ENUM_MAX:
break;
}
debug(28, 1) ("aclDumpGeneric: no case for ACL type %d\n", a->type);
return NULL;
}
--------------x----------------------------x--------------------------x-----------------
#include <iostream.h>
#include <fstream.h>
#include <conio.h>
#include <stdio.h>
int main (void)
{
FILE *in;
char *matriz[] = {0};
int i = 0;
clrscr();
if ((in = fopen("BL.TXT", "rt")) == NULL)
{
fprintf(stderr, "Cannot open input file.\n");
return 1;
}
while (!feof(in))
{
fputc(fgets(in), matriz[i]);
i++;
}
printf ("resultado= %c",matriz[1]);
getch();
fclose(in);
return 0;
}
----------x------------------------x-------------------------x----------------
#include <stdio.h>
int main(void)
{
FILE *in, *out;
if ((in = fopen("BL.TXT", "rt"))
== NULL)
{
fprintf(stderr, "Cannot open input file.\n");
return 1;
}
if ((out = fopen("BL2.TXT", "wt"))
== NULL)
{
fprintf(stderr, "Cannot open output file.\n");
return 1;
}
while (!feof(in))
fputc(fgetc(in), out);
fclose(in);
fclose(out);
return 0;
}
------------x----------------------x--------------------x--------------------------x-----------------#!/bin/bash
read i
echo $i >> /home/squid/squid
cat /home/squid/squid | awk -F "/" '{print $3}' >> /home/squid/squid2
perl /home/squid/www/cgi-bin/teste.pl
#/usr/share/squid/erros/Portuguese/ERR_ACCESS_DENIED
#return i
---------x--------------x-----------------x-----------------x-------
IFS="
"
for url in `cat` ; do
echo $url
case $url in
*jpg)
echo "http://erro.html" ;;
*)
echo $url ;;
esac
done
------------x-------------------x--------------------x--------------------x-----------------------#!/usr/bin/perl5.8.1
use DBI;
open (teste, "teste.txt");
#Conexao com o BD
my $db = DBI->connect("dbi:Pg:dbname=bdblack","postgres","123456");
my $url = <teste>;
@array = split(/[\s]/,$url);
print "$_\n" foreach (@array);
my $query = "SELECT * FROM sites WHERE url = '@array[0]' OR dominio = '$url'";
my $res;
$res = $db->do($query);
if ($res == 1){
print ("\nSite Bloqueado\n");
}
else{
print ("\nSite Livre\n");
}
#Fecha a conexao
$db -> disconnect();
close (teste);
exit();
---------x-------------------------x----------------------------x-------------------------x-----------------#!/usr/bin/perl5.8.1
use DBI;
open (teste, "teste.txt");
#Conexao com o BD
my $db = DBI->connect("dbi:Pg:dbname=bdblack","postgres","123456");
my $url = <teste>;
@array = split(/[\s]/,$url);
my $query = "SELECT * FROM sites WHERE url = '@array[0]' OR dominio = '$url'";
my $res;
$res = $db->do($query);
if ($res == 1){
print ("\nSite Bloqueado\n");
}
else{
print ("\nSite Livre\n");
}
#Fecha a conexao
$db -> disconnect();
close (teste);
exit();
----------------------x------------------------x-----------------------------------x-------------------------#!/usr/bin/perl5.8.1
use DBI;
#Conexao com o BD
my $db = DBI->connect("dbi:Pg:dbname=bdblack","postgres","123456");
#Inserindo dados para consulta
print ("Site: ");
chomp (my $url = <STDIN>);
#Query para consulta no BD
my $query = "SELECT * FROM sites WHERE url = '$url' OR dominio = '$url'";
my $res; #Variavel para armazenar o retorno da consulta 1 ou 0
$res = $db->do($query); #Executa consulta e armazena o resultado na var. res
#Testa a condicao da variavel res
if ($res == 1){
print ("\nSite Bloqueado\n");
}
else{
print ("\nSite Livre\n");
}
#Fecha a conexao
$db -> disconnect();
exit();
---------x-------------------x------------------x-------------x---------############Copiando os dados para a tabela######################
copy squid from '/home/squid/squid.txt' delimiter as ',';
################################################################
#########Criando a tabela direto no banco bdblack################
psql -f tabelasites bdblack
#################################################################
cat urls | awk -F "/" '{print$1"/"$2","$2}'
------x------------------x-----------------------x---------------x--------create table sites (url varchar(300), dominio varchar (300));
-------x----------------x------------------x-------------x-------
#!/usr/bin/perl5.8.1
use DBI;
#Conexao com o BD
my $db = DBI->connect("dbi:Pg:dbname=bdblack","postgres","123456");
#Entrada de um valor para consulta
print("Digite um site: ");
chomp ( my $url = <STDIN> );
#Query para consulta
my $query = "SELECT * FROM sites WHERE url = '$url'";
#Executando consulta
$db->do( $query );
#Preparando uma consulta
my $sql = $db->prepare(q{ SELECT * FROM sites where url = "$url" });
$sql->execute();
#Imprimindo tabela
my @array;
while ( @array = $sql -> fetchrow_array() ){
write();
}
format STDOUT =
@<<<<<<<<<<<<<<<<<<<<<<<<@<<<<<<<<<<<<<<<<<<<<<
$array[0],$array[1]
.
#Fecha a conexao
$db -> disconnect();
exit();
-----------x---------------------x----------------------x----------------#!/usr/bin/perl5.8.1
use DBI;
#Conexao com o BD
my $db = DBI->connect("dbi:Pg:dbname=bdblack","postgres","123456");
#Handle para consulta
my $sql = $db -> prepare(q{SELECT * FROM sites});
#Executa consulta
$sql -> execute();
#Entrada para busca
print("Digite um site para ser pesquisado: ");
chomp( my $url_dom = <STDIN> );
#Imprimir valores
while (($url_dom) = $sql -> fetchrow_array())
{
print $url_dom;
}
#Mostra a quantidade de linhas retornadas
printf ("\nForam encontrados %d resultados\n",$sql -> rows);
#Finaliza Query
$sql -> finish();
#Fecha a conexao
$db -> disconnect();
exit();
--------x-----------------x-----------------x--------------------x------#!/usr/bin/perl5.8.1
use DBI;
#Conexao com o BD
my $db = DBI->connect("dbi:Pg:dbname=bdblack","postgres","123456");
#Inserindo dados para consulta
print ("Site: ");
chomp (my $url = <STDIN>);
#Query para consulta no BD
my $query = "SELECT * FROM squid WHERE url = '$url'";
my $res; #Variavel para armazenar o retorno da consulta 1 ou 0
$res = $db->do($query); #Executa consulta e armazena o resultado na var. res
#Testa a condicao da variavel res
if ($res == 1){
print ("\nSite Bloqueado\n");
}
else{
print ("\nSite Livre\n");
}
#Fecha a conexao
$db -> disconnect();
exit();
-----------x---------------x------------------x--------------x------------postgresql-8.1.4.tar
per-libwww-per-5.803-norch.tar
alien_8.64.tar
squid-2.5.stable13.tar
perl-CGU-2.81.tar
per-URi-1.31
perl-CPAn-1.61
perl-5.8.1
DBI-1.52.tar
--------------x---------------x------------------x-----------------Ideias do grupo
1 - Uso de banco de dados para acessar os dados mais rapidamente.
2 - Uso do programa diskd para as versões mais 2.4 até stable.
3 - Uso de parametros habilitados na hora da compilação.
4 - Uso de outros proxy's como alternativa para a solução do problema.
5 - Hardware especializado.
6 - Melhora no algoritmo de ordenação e de busca.
7 - criação de uma tabela de indicação de hardware especifico para a quantidade
de usuarios.
8 - cada requisição do browser é considerada um GET
Referências
ANDRADE,
Jociel.
Instalando
e
configurando
o
Squid.
<http://geocities.yahoo.com.br/cesarakg/installing-configuring-squid.html>, Acesso em 15
de abril de 2006.
BASTOS,
Eri
Ramos.
Configurando
um
Squid
Ninja.
<http://www.linuxman.pro.br/squid/>.Acesso em 02 de maio de 2006.
CAMPOS,
Augusto
C.
Squid
o
Melhor
Proxy.
<http://squid.linuxit.com.br/download/squid/antigos/guiasquid-txt-1.2.txt>, Acesso em 25
de abril 04 de 2006.
CIPRIANO,
Luis
Alberto
Garcia.
Configurando
Oops.
<http://zipper.paco.net/~igor/oops.eng/features.html>, Acesso em 04 de março de 2006.
Deitel, Deitle; Mcphie, Nieto. Perl Como Programar. 3. ed. São Paulo. Bookman, 2005.
Enciclopédia
Bozolinux.
Squid.
<http://br.bozolinux.org/enciclopedia/index.php?
title=Squid>.Acesso em 02 de maio de 2006.
Ferreira, Ruben e. Linux - Guia do Administrador do Sistema.1. ed. São Paulo.
Novatec, 2003.
JÚNIOR,
Walter
Implementação
Flávio
Pimenta.
em
MPI.
Hiperquicksort:
Uma
Análise
Prática
com
<http://www.comp.ufla.br/monografias/ano2002/Hiper
quicksort_uma_analise_pratica_com_implementacao_em_MP.pdf>,Acesso
em
14
de
março de 2006.
MARTINS,
Stéfano.
Guia
Sobre
Squid/Proxy
Transparente.
<http://squid.linuxit.com.br/download/squid/antigos/guiasquid-txt-1.2.txt>. Acesso em 11 de
março de 2006.
Oliveira, Alvaro Mendes de.Squid Plus com AD, redirector, controle de banda e
relatórios.<http://www.vivaolinux.com.br/artigos/verArtigo.php?codigo=4716> .Acesso em
23 de setembro de 2006.
Paes, Gustavo. Instalando e configurando os módulos do kernel 2.6 no Slackware.
<http://www.slackware-rasil.com.br/web_site/artigos/artigo_completo.php?aid=60>
Acesso em 15 de Agosto de 2006.
RESENES, Jonas. Configurando o Squid no Slackware.
<http://www.vivaolinux.com.br/artigos/verArtigo.php?codigo=1833&pagina=2#>.
Acesso em 18 de fevereiro de 2006.
REGULY,Alvaro.Instalando
Squid.
e
configurando
o
.<http://www.sistemasabertos.com.br/twiki/bin/viewpub/Pub/ArtigoServidorProxy?
skin=print1>, Acesso em 15 abril de 2006.
REIS, Cristiano Fernandes dos reis. Desenho de rede ideal de um serviço Proxy.
São Paulo. 2006.
SATO,Yutaka. Configurando Dansguardian. <http://www.dansguardian.org>,
Acesso em 17 de Abril de 2006.
SILVA, Hedwio Carvalho.Configurando o Dansguardian. http://www.dansguardian.org>,
Acesso em 23 de Abril de 2006.
Stones, Richard; Matthew, Neil. Professional Linux Programando.
2. ed. São Paulo. Makron Books, 2002.
THOENY,Peter. Monografia Proxy.
<http://www.comp.ufla.br/monografias/ano2002/Hiperquicksort_uma_analise_pratica_com
_implementacao_em_MP.pdf>, Acesso em 02 de Maio de 2006.
VESPERMAN, Jennifer. Instalando e Configurando o Squid.
<http://br.geocities.com/cesarakg/installing-configuring-squid.html>. Acesso em 11 de
Março de 2006.
Wolfer, Thomas. Aumente a taxa de transferencia de dados de seus discos IDE com o
hdparm. Linux Magazine. São Paulo: Setembro, ano 1, n 2, set 2004. pg. 36.
------------------------------////////////////-----------------------------------------------------------Data: 14/03/2006
Hora:21:00:00
http://www.comp.ufla.br/monografias/ano2002/Hiperquicksort_uma_analise_pratica_com_i
mplementacao_em_MP.pdf
http://pt.wikipedia.org/wiki/Lista_de_algoritmos#Algoritmos_de_Classifica.C3.A7.C3.A3o
http://www.unicamp.br/~hans/mc102/pascal/algoritmo/_buscaBinaria.html
----------------------------//////////////////---------------------------------------------------------------------------------------//////////////////-----------------------------------------------------------Data: 11/03/2006
Hora: 14:00:00
http://squid.linuxit.com.br/download/squid/antigos/guiasquid-txt-1.2.txt
http://www.sistemasabertos.com.br/twiki/bin/viewpub/Pub/ArtigoServidorProxy?skin=print1
http://geocities.yahoo.com.br/cesarakg/installing-configuring-squid.html
----------------------------//////////////////------------------------------------------------------------
----------------------------//////////////////-----------------------------------------------------------Data: 18/02/2006
Hora: 14:00:00
http://www.squid-cache.org/Doc/Prog-Guide/prog-guide-3.html
http://www.linhadecodigo.com.br/livros.asp?id=575
http://www.ginux.ufla.br/documentacao/monografias.html
http://www.vivaolinux.com.br/artigos/verArtigo.php?codigo=1833&pagina=2#
http://urlblacklist.com/
----------------------------//////////////////-----------------------------------------------------------------------------------------////////////////-----------------------------------------------------------Data: 14/03/2006
Hora:21:00:00
http://pt.wikipedia.org/wiki/Lista_de_algoritmos#Algoritmos_de_Classifica.C3.A7.C3.A3o
**http://www.unicamp.br/~hans/mc102/pascal/algoritmo/_buscaBinaria.html
----------------------------//////////////////---------------------------------------------------------------------------------------//////////////////-----------------------------------------------------------Data: 11/03/2006
Hora: 14:00:00
**http://www.sistemasabertos.com.br/twiki/bin/viewpub/Pub/ArtigoServidorProxy?
skin=print1
----------------------------//////////////////------------------------------------------------------------
----------------------------//////////////////-----------------------------------------------------------Data: 18/02/2006
Hora: 14:00:00
**http://www.squid-cache.org/Doc/Prog-Guide/prog-guide-3.html
**http://www.ginux.ufla.br/documentacao/monografias.html
**http://urlblacklist.com/
----------------------------//////////////////-----------------------------------------------------------Data: 16/04/2006
Hora: 14:50:00
ftp://www.delegate.org/pub/DeleGate/Manual.htm#DESCRIPTION
**http://lists.debian.org/debian-l10n-portuguese/2001/10/msg00052.html
---------------------------////////////////////-------------------------------------------------------------------------------------////////////////////----------------------------------------------------------Data: 02/05/2006
Hora: 17:13:00
**http://www.inf.ufes.br/~proinfo/aulas_via_chat/Setembro-01/turma2_0109.htm
**http://zipper.paco.net/~igor/oops.eng/features.html
**http://www.dansguardian.org
**http://www.delegate.org
http://www.inf.ufes.br/~proinfo/aulas_via_chat/Setembro-01/turma2_0109.htm
http://br.bozolinux.org/enciclopedia/index.php?title=Squid
http://www.linuxman.pro.br/squid/index.t2t
http://www.slackwarenaveia.org/modules.php?name=Sections&op=printpage&artid=80
http://www.linuxman.pro.br/squid/
http://zipper.paco.net/~igor/oops.eng/features.html
http://www.dansguardian.org
http://www.delegate.org
--------------------------///////////////////////---------------------------------------------------------
Lista de Siglas e Abreviaturas
ACL (Access Control List ou Lista de Controle de Acesso): definida pela área de ciência da
computação como uma lista que define quem tem permissão de acesso a certos serviços. Isso é para
quem um servidor deve permitir ou negar determinada tarefa. É normalmente uma lista de
princípios com os tipos de acesso definido para cada usuário ou grupo.
ADSL (Asymmetric Digital Subscriber Line): é um formato de DSL, uma tecnologia de
comunicação de dados que permite uma transmissão de dados mais rápida através de linhas de
telefone do que um modem convencional pode oferecer.
Backbone: No contexto de redes de computadores, o backbone (traduzindo para português, espinha
dorsal) designa o esquema de ligações centrais de um sistema mais amplo, tipicamente de elevado
débito (velocidade, no português do Brasil) relativamente à periferia.
Backup: Refere-se à cópia de dados de um dispositivo para o outro com o objetivo de
posteriormente os recuperar (os dados), caso haja algum problema.
Browser: (também conhecido como web browser) é um programa que habilita seus usuários a
interagirem com documentos HTML hospedados em um servidor Web.
Cache: É um dispositivo de acesso rápido, interno a um sistema, que serve de intermediário entre
um operador de um processo e o dispositivo de armazenamento ao qual esse operador acede. A
vantagem principal na utilização de uma cache consiste em evitar o acesso ao dispositivo de
armazenamento - que pode ser demorado - e que vale a pena armazenar as informações procuradas
em meio mais rápido.
CGI (Common Gateway Interface): Consiste numa importante tecnologia que permite gerar
páginas dinâmicas permitindo a um navegador passar parâmetros para um programa alojado num
servidor web.
Dial-up: É um tipo de acesso à Internet no qual uma pessoa usa um modem e uma linha telefônica
para se ligar a um nó de uma rede de computadores do ISP. A partir desse momento, o ISP
encarrega-se de fazer o routing para a Internet.
DNS (Domain Name System - Sistema de Nomes de Domínios): É um sistema de gerenciamento
de nomes hierárquico.
Ethernet: É uma tecnologia de interconexão para redes locais - Local Area Networks (LAN) baseada no envio de pacotes. Ela define cabeamento e sinais elétricos para a camada física, e
formato de pacotes e protocolos para a camada de controle de acesso ao meio (Media Access
Control - MAC) do modelo OSI. A Ethernet foi padronizada pelo IEEE como 802.3. A partir dos
anos 90, ela vem sendo a tecnologia de LAN mais amplamente utilizada e tem tomado grande parte
do espaço de outros padrões de rede como Token Ring, FDDI e ARCNET.
Expressão Regular: Um padrão a ser usado para procurar ou substituir palavras ou grupos de
palavras. É um meio preciso de se fazer buscas de determinadas porções de texto.
Firewall: É o nome dado ao dispositivo de rede que tem por função regular o tráfego de rede entre
redes distintas e impedir a transmissão de dados nocivos ou não autorizados de uma rede a outra.
Dentro deste conceito incluem-se, geralmente, os filtros de pacotes e Proxy de protocolos.
FTP (File Transfer Protocol - Protocolo de Transferência de Arquivos): É uma forma bastante
rápida e versátil de transferir arquivos, sendo uma das mais usadas na internet.
Gateway: É uma máquina intermediária geralmente destinada a interligar redes, separar domínios
de colisão, ou mesmo traduzir protocolos. Exemplos de gateway podem ser os routers (ou
roteadores) e firewalls, já que ambos servem de intermediários entre o utilizador e a rede. Um Proxy
também pode ser interpretado como um gateway (embora em outro nível, aquele da camada em que
opera), já que serve de intermediário também.
Gopher: É um protocolo de redes de computadores que foi desenhado para indexar repositórios de
documentos na Internet.
Host: É qualquer máquina ou computador conectado a uma rede. Os hosts variam de computadores
pessoais a supercomputadores, dentre outros equipamentos, como roteadores.
HTML (HyperText Markup Language - Linguagem de Formatação de Hipertexto): Trata-se
de uma linguagem de marcação utilizada para produzir páginas na Internet. De modo geral são
documentos de texto escritos em códigos que podem ser interpretados pelos browsers para exibir as
páginas da World Wide Web.
HTTP (HyperText Transfer Protocol - Protocolo de Transferência de Hipertexto): É um
protocolo da camada de "Aplicação" do modelo OSI, utilizado para transferência de dados na World
Wide Web. Esse é o protocolo da World Wide Web (www). O mesmo transfere dados de hipermidia (imagens, sons e textos). Algumas de suas características são: geralmente este protocolo,
utiliza a porta 80 e é usado para a comunicação de "sites".
ICP (Infra-estrutura de Chaves Públicas): Uma Infra-Estrutura de Chaves Públicas é um órgão
ou inciativa pública ou privada para a organização de uma estrutura de emissão de chaves públicas,
baseando-se no princípio da terceira parte confiável, oferecendo uma mediação de acreditação e
confiança em transações entre partes que utilizam certificados digitais, bem como se
responsabilizando pela emissão de tais certificados, assumindo-se então como a parte confiável
destas transações. A infra-estrutura de chaves públicas do Brasil é a Infra-Estrutura de Chaves
Públicas Brasileira, ou ICP-Brasil.
ICQ: É um programa de comunicação instantânea pela Internet que foi o mais popular durante
anos.
IMAP (Internet Message Access Protocol): É um protocolo de gerenciamento de correio
eletrônico superior em recursos ao POP3 - protocolo que a maioria dos provedores oferece aos seus
assinantes. A última versão é o IMAP4. O mais interessante é que as mensagens ficam armazenadas
no servidor e o internauta pode ter acesso a suas pastas e mensagens em qualquer computador.
IP (Internet Protocol - Protocolo de Internet): É um protocolo usado entre duas máquinas em
rede para encaminhamento dos dados.
ISP (Internet Service Provider): Oferece principalmente serviço de acesso à internet, agregando a
ele outros serviços relacionados, tais como "e-mail", "hospedagem de sites" ou blogs, entre outros.
Kernel: É entendido como o núcleo do Sistema Operacional ou, numa tradução literal, cerne. Ele
representa a camada mais baixa de interface com o Hardware, sendo responsável por gerenciar os
recursos do sistema computacional como um todo. É no kernel que estão definidas funções para
operação com periféricos (mouse, discos, impressoras, interface serial/interface paralela),
gerenciamento de memória, entre outros. Resumidamente, o kernel é um conjunto de programas que
fornece para os programas de usuário (aplicativos) uma interface para utilizar os recursos do
sistema.
Link: É uma referência num documento em hipertexto a outro documento ou a outro recurso.
Login: É um conjunto de caracteres solicitado para os usuários que por algum motivo necessitam
acessar algum sistema computacional. Geralmente os sistemas computacionais solicitam um login e
uma senha para a liberação do acesso.
Logs: É o termo utilizado para descrever o processo de registro de eventos relevantes num sistema
computacional.
MIME (Multipurpose Internet Mail Extensions): É uma norma da Internet para o formato das
mensagens de correio eletrônico.
NAT (Network Address Translation): Também conhecido como masquerading é uma técnica que
consiste em reescrever os endereços IP de origem de um pacote que passam sobre um router ou
firewall de maneira que um computador de uma rede interna tenha acesso ao exterior (rede pública).
NFS (Network File System): É um modelo de sistema de arquivos, que tem como função
centralizar arquivos em um servidor, formando assim um diretório virtual.
NNTP (Network News Transfer Protocol): É um protocolo da internet para grupos de discussão
da chamada usenet.
OSI (Open Systems Interconnection): É um conjunto de padrões ISO relativo à comunicação de
dados.
POP (Post Office Protocol (POP3)): É um protocolo utilizado no acesso remoto a uma caixa de
correio eletrônico.
RAID (Redundant Array of Independent Disks - Conjunto Redundante de Discos): É um meio
de se criar uma unidade virtual composta por vários discos individuais, com a finalidade de
duplicação (redundância, recuperação de falhas) ou balanceamento (operações I/O em paralelo).
SCSI (Small Computer System Interface): A tecnologia SCSI foi criada para acelerar a taxa de
transferência de dados entre dispositivos de um computador, desde que tais periféricos sejam
compatíveis com o padrão.
SMTP (Simple Mail Transfer Protocol): É o padrão de fato para envio de e-mail através da
Internet.
SSL (Secure Sockets Layer): É um protocolo criptográfico que provêem comunicação segura na
Internet para coisas como e-mail, navegação por páginas, e outros tipos de transferência de dados.
Tag: São estruturas de linguagem de marcação que consistem em breves instruções, tendo uma
marca de início e outra de fim.
TCP (Transmission Control Protocol): É um dos protocolos sob os quais assenta o núcleo da
Internet nos dias de hoje. A versatilidade e robustez deste protocolo tornou-o adequado para redes
globais, já que este verifica se os dados são enviados de forma correta, na seqüência apropriada e
sem erros, pela rede.
Telnet: É um protocolo cliente-servidor de comunicações usado para permitir a comunicação entre
computadores ligados numa rede, baseado em TCP.
TTL (Time to Live): Significa o número de máquinas que os pacotes podem demorar numa rede de
computadores antes de serem descartados (máx. 255).
UDP: Dá às aplicações acesso direto ao serviço de entrega de datagramas, como o serviço de
entrega que o IP dá.
URL (Universal Resource Locator - Localizador Universal de Recursos): É o endereço de um
recurso, disponível em uma rede; seja a Internet, ou uma rede corporativa, uma intranet.
WEB: É uma rede de computadores na Internet que fornece informação em forma de
hipertexto.