Escolar Documentos
Profissional Documentos
Cultura Documentos
PROJETO SQUID
Trabalho apresentado Universidade Ibirapuera para obteno do ttulo de Bacharel em Cincia da Computao
So Paulo 2006
Dedicatria
Este trabalho foi desenvolvimento em conjunto de trs bons amigos de faculdade que se conheceram e tornaram-se bom amigos, e dedicam todo o seu contedo 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 disposio toda a sua ateno 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 caractersticas que o tornam um dos melhores. feito um detalhamento a respeito de sua implementao e como ele usado como servidor de Proxy e sistemas para esta finalidade. Apesar das operaes do mesmo, (contm um problema em especifico que o seu desempenho no recebimento de um nmero elevado de requisies). Este o objetivo deste trabalho, onde apresentamos solues para a resoluo desta deficincia.
Palavras-Chaves:
Proxy, Squid, algoritmos de ordenao 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.
Sumrio
1 Introduo...................................................................................................................................01 1.1 Objetivo........................................................................................................................... 03 1.2 Estrutura......................................................................................................................... .03 Captulo 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 Caractersticas 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 Autenticao.............................................................................................................. 14 2.5.3 - Listas de controles de acesso.............................................. ...................................14 2.5.4 - Proxy para SSL........................................................................................................... 14 Captulo 3 Squid........................................................................................................................... 15 3.1 - Caractersticas do Proxy Squid..................................................................................... 16 3.1.1 - Restries de acesso........................................................... ....................................16 3.1.2 - Arquivo de configurao............................................................................................ 18 3.1.3 - Funo 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 - Referncias de conexo................................................................................................. 26 3.6 Vantagens...................................................................................................................... 28 Captulo 4 - Conhecendo Algumas Solues................................................................................. 29 4.1 Configurao................................................................................................................... 29 4.2 Hdparm........................................................................................................................... 29 4.3 - Banco de Dados............................................................................................................... 29 4.4 - Alterao do Cdigo fonte............................................................................................... 30 4.5 - Compilao do Kernel..................................................................................................... 30 Captulo 5 - Aplicando a soluo escolhida................................................. ..............................31 5.1 - A Escolha......................................................................................................................... 31 5.2 - Desenvolvendo a Soluo................................................................ ............................31 5.3 - Detalhamento do processo............................................................................................... 32
5.4 - Introduo ao Perl......................................................................................................... 34 5.4.1 - Caractersticas do Perl...................................................................................... 35 5.5 - Introduo ao PostgreSQL.............................................................................................36 5.6 - Outras solues aplicadas.............................................................................................. 37 5.6.1 - HDparm................................................................................ .........................37 5.6.2 Kernel............................................................................................................. 39 Captulo 6 Concluso....................................................................................................................42 Lista de anexos................................................................................................................................. 43 Referncias....................................................................................................................................... 49
1 - Introduo
A popularizao da Web1 tem provocado srios problemas de desempenho nos acessos Internet, de forma que a reduo do tempo tem se tornado um fator extremamente relevante. O nmero de usurios que se conectam na rede cresce de forma acentuada. O tempo para se recuperar um documento Web depende de determinados fatores (tipo de conexo, tamanho do documento, localizao do mesmo). Para minimizar as conseqncias deste crescimento, alguns mtodos podem ser adotados como a utilizao de um servidor mais rpido, alterao dos meios fsicos (Cabos, Roteadores, Switches, etc.) de forma que se aumente a banda. Contudo, isto alm de no ser economicamente vivel, pode no resolver o problema, uma vez que so numerosos os fatores que envolvem uma nica transao Web. Alternativas como o cache de pginas Web, espelhamento de arquivos entre outros tm sido aplicados para resolver determinadas situaes inerentes rede. O procedimento de implantao de um sistema de cache de navegao que armazene localmente objetos como pginas HTML2 (HyperText Markup Language), imagens e arquivos da Internet, podem melhorar a qualidade do servio fornecido aos usurios. Os servidores de Proxy ajudam a diminuir de forma significativa o tempo mdio de acesso a pginas e a transferncia de arquivos, porque muitos deles (pginas Web, arquivos, fotos, etc.) so requisitados mais de uma vez, entretanto, exceto na primeira vez estas requisies so feitas remotamente, ou seja, as pginas so carregadas direto do servidor que esto hospedadas, caso contrrio s requisies so atendidas de forma local.
1 2
Web: Rede de computadores na Internet que fornece informao em forma de hipertexto. HTML: um dispositivo de acesso rpido, interno a um sistema, que serve de intermedirio entre um operador de um processo e o dispositivo de armazenamento.
De uma forma geral os visualizadores de pginas Web conhecidos como browsers fazem conexo direta com os servidores remotos. Entretanto, eles podem ser configurados para se conectar a um servidor Proxy. Assim, quando um usurio requisitar uma pgina, o browser primeiramente verifica seu cache local. Se a pgina URL1 no encontrada, ele a requisita para o servidor Proxy local. Se este tm a cpia e ela no expirou, ele a retorna imediatamente, caracterizando desta forma o conceito de cache hit. Caso esta no esteja no cache, ele entrar em contato com o servidor remoto e far a transferncia, mantendo uma cpia opcional em seu cache e enviando uma cpia para a mquina do usurio, neste caso, haver o que chamamos de conceito cache miss. Uma das funes do Proxy denominada de Filtro. Este filtro usado para permitir ou negar o acesso Internet ou a determinados sites, ou seja, controle de contedo. Administradores podem criar regras conforme suas polticas de segurana para filtrar requisies baseadas no endereo IP 2
(Internet Protocol) do cliente, domnios, redes e URL do objeto requisitado, bloqueando assim requisies consideradas imprprias a poltica adotada. Tais funcionalidades so usadas principalmente em escolas e em organizaes que utilizam o critrio de permisso para o acesso a pginas que realmente sejam de seu interesse. O filtro podem conter regras simples baseados em uma lista de pginas Web, bem como conter regras mais complexas.
1 2
URL: o endereo de um recurso, disponvel em uma rede; seja a Internet, ou uma rede corporativa ou uma intranet. IP: um protocolo usado entre duas mquinas em rede para encaminhamento dos dados.
1.1 - Objetivo
O objetivo deste trabalho a implementao e a otimizao 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 requisies ACL 1 (Access Control List). O seu desempenho se torna crtico quando a quantidade de usurios 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 considervel de memria, e para compensar tal situao, necessrio disponibilizar um computador mais potente o que acaba onerando os custos significativamente, pois a cada demanda de processos necessrio ajustar o hardware. O Squid possue esta deficincia, o que estamos propondo minimizar esta situao aplicando solues que so a melhora do programa do Squid como um front-end ideal para a soluo e tambm melhorando a entrada e sada do disco rgido, e aplicando uma configurao ideal para o hardware diretamente no kernel influenciando diretamente no desempenho do mesmo e diminuindo a sobrecarga da memria efetuada durante o trabalho do Proxy.
1.2 - Estrutura
Para atingir este objetivo o trabalho foi estruturado da seguinte forma: Captulo 2: Proxy; Captulo 3: Squid; Captulo 4: Conhecendo algumas possveis solues; Captulo 5: Aplicando a soluo escolhida.
ACL: normalmente uma lista de princpios com os tipos de acesso definido para cada usurio ou grupo.
O Proxy surgiu da necessidade de conectar uma rede local Internet atravs de um computador da rede que compartilha sua conexo com as mquinas 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 mquinas tenham acesso externo, ou seja, a conexo com a Internet. Geralmente, mquinas da rede interna no possuem endereos vlidos na Internet, primeiro pelo fato da segurana nas redes privadas e tambm devido falta de IPs vlidos, portanto, no tm uma conexo direta com a Internet. Assim, toda solicitao de conexo de uma mquina 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 solicitao para a mquina da rede local. comum termos o Proxy como conexo direta com a Internet. Vejamos um exemplo de um esquema de servidor Proxy. Figura 1.
RAM: Randomic Access Memory HTTP: um protocolo da camada de "Aplicao" do modelo OSI, utilizado para transferncia de dados na Internet. 3 HTTPS: um protocolo da camada de "Aplicao" do modelo OSI, com implementao de segurana. 4 FTP: uma forma bastante rpida e verstil de transferir arquivos, sendo uma das mais usadas na internet.
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
contedo, na qual possui vrios programadores como desenvolvedores do projeto pelo mundo. geralmente disponibilizado por padro 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 eletrnico (SMTP2 e POP3) e ICQ4.
1
Gopher: um protocolo de redes de computadores que foi desenhado para indexar repositrios de documentos na Internet. 2 SMTP: o padro de fato para envio de e-mail atravs da Internet. 3 POP: um protocolo utilizado no acesso remoto a uma caixa de correio eletrnico. 4 ICQ: um programa de comunicao instantnea pela Internet.
2.2.2 - Delegate
Este tambm um Proxy interessante, de autoria de Yutaka Sato (2006), o Delegate um Proxy Server 5multiplataforma com relays e vrios protocolos de aplicao 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 comunicao entre usurios e clientes, onde uma comunicao direta impossvel, ineficiente, ou inconveniente, conforme Sato (2006).
1
Telnet: um protocolo cliente-servidor de comunicaes usado para permitir a comunicao entre computadores ligados numa rede, baseado em TCP. 2 NNTP: um protocolo da internet para grupos de discusso da chamada usenet. 3 SMTP: um protocolo relativamente simples, baseado em texto simples, em que um ou vrios destinatrios de uma mensagem so especificados, sendo depois a mensagem transferida. 4 IMAP: um protocolo de gerenciamento de correio eletrnico superior em recursos ao POP3 5 LPR: a porta de impresso em Linux. 6 LDAP: Servio de rede que disponibiliza integrao de senhas para qualquer servio. 7 ICP: Uma Infra-Estrutura de Chaves Pblicas um rgo ou inciativa pblica ou privada para a organizao de uma estrutura de emisso de chaves pblicas. 8 DNS: um sistema de gerenciamento de nomes hierrquico. 9 SSL: um protocolo criptogrfico que provem comunicao segura na Internet para coisas como e-mail, navegao por pginas, e outros tipos de transferncia de dados 10 Socks: um protocolo de internet que permite que aplicaes cliente-servidor usem transparentemente o servio 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 caractersticas conforme (Cipriano 2006), : HTTP/1.1 (ainda sem conexes persistentes) e FTP; Ele est pronto para servir pedidos imediatamente aps iniciado; Armazenamentos em disco so checados em segundo plano, enquanto servem pedidos diretamente da rede; Reconfigurao limpa em Sighup1 e sem sesses quebradas, novas configuraes aplicadas a novas conexes; Arquivo de configurao e ACLs fceis de ler e entender; Controle de largura de banda; Diversos tipos de mdulos existem como gerao de logs, acesso, sada, relato de erros, filtragem de URL, etc; Objetos so armazenados em arquivos grandes e sem esquema de objeto por arquivo.
2.2.4 - Dansguardian
uma ferramenta capaz de filtrar acessos a Internet com base em diferentes critrios, possui filtros com as seguintes caractersticas, conforme descrito por Silva (2006). Filtros de domnios ou URLs com um desempenho visivelmente superior a outras ferramentas; Filtros baseados em frases associadas pornografia ou consideradas inapropriadas; Filtros por figuras ou por tipo de contedos (MIME1); Filtros por extenso de arquivos, como: .exe, .dll, .scr, etc; Filtro com caractrsticas em que possvel bloquear ou limitar upload na Internet. A ferramenta difere da maioria disponvel no mercado pelo fato de no funcionar apenas como filtro de URL, mas tambm como um efetivo filtro de contedos de pginas Web. Pois, faz uma varredura do contedo de cada pgina acessada por seus usurios e no somente uma liberao ou proibio do nome do site ou da URL acessada. Este filtro de contedo funciona em conjunto com qualquer Proxy, podendo ser instalado em sistemas operacionais Linux, FreeBSD, OpenBSD, NetBSD, Mac OSX e Solaris. O Dansguardian no tem caractersticas de Proxy, portanto obrigatrio o uso de um servidor Proxy para que a ferramenta seja implementada, embora ele tenha sido citado neste trabalho por ser relevante suas funes. Nas solues comumente encontradas no mercado, o filtro de contedo recebe as requisies do navegador do usurio, aplica as restries estabelecidas ou as excees configuradas e, em seguida, passa a requisio para o Proxy. Este faz o seu papel que a intermediao entre o cliente e o servidor a ser acessado. No processamento interno de arquivos contendo proibies e excees, existe uma ordem prestabelecida.
1
MIME: uma norma da Internet para o formato das mensagens de correio eletrnico .
Apesar do Dansguardian no ter caractersticas de Proxy o mesmo foi citado apenas para fim de conhecimento, uma vez que o objetivo deste trabalho demonstrar os diversos tipos de aplicaes para otimizao do Proxy Squid, procurando a melhor soluo para desempenho do mesmo tornando-o to eficiente quanto o Dansguardian no processo de filtro de contedos, pois quando o Squid utiliza uma base muito extensa (Black-list1), consequentemente passa a utilizar muita memria e se torna lento demais sobrecarregando consideravelmente a rede.
servio bsico de um Proxy. Mas um bom Proxy deve ainda prover vrias outras funcionalidades complementares conforme Peter Thoeny (2002). Existem duas caractersticas principais de Proxy, na qual so definidos, como Proxy Transparente e Proxy Controlado, conforme Martins (2006).
em uma grande rede; Como j dito anteriormente, o uso do Proxy transparente fora o cliente a passar pelo Proxy; Com a configurao do Proxy transparente, todos os servios ficam disponveis 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 servios como: SSH, Telnet, E-mail, etc; Outro recurso do Proxy transparente que ele funciona como uma maneira de bloquear acesso evitando que aqueles usurios mais espertos retirem as definies do Proxy de dentro do navegador, podendo assim visitar sites proibidos; Com o Proxy transparente todas as requisies feitas porta 80 so automtica redirecionadas para a porta do Squid, e assim fica virtualmente impossvel de sair para a Internet.
2.5.2 - Autenticao
Ao requisitar uma pgina ser exibido uma caixa solicitando ao usurio um login e uma senha, e com base nesta autenticao de regras estabelecidas pelas ACL o usurio poder ter ou no acesso a pgina requisitada.
Capitulo 3 - Squid
O Squid caracteriza-se em um software especializado, que faz operao de Proxy de Web e FTP, completamente livre e com excelente suporte para operao em servidores Linux. Com o Squid voc pode instalar um servidor Linux com acesso Internet, e fazer com que outras mquinas clientes (usando sistemas operacionais como: Linux, Windows ou outros) acessem pginas Web e sites FTP atravs do servidor Linux, as mquinas clientes precisam somente estar com os seus (gateway) padres apontados para o servidor Proxy. O Squid d acesso a servios como HTTP, HTTPS e FTP. Mesmo em redes onde seria possvel instalar IP (masquerading), muitos administradores optam por limitar o acesso direto das mquinas internas Web, por vrias razes, entre as quais se incluem a segurana e o controle de acesso (atravs de mecanismos de restrio e de Log). O recurso que mais atrai ateno no Squid o cache de pginas. Como em geral o Link entre as mquinas 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 pginas acessadas, de forma a no ter que buscar novamente na Internet uma pgina que tenha sido recentemente vista por outro usurio da mesma rede. Naturalmente voc pode configurar o tempo de armazenamento de cada pgina no cache, e o protocolo HTTP tm recursos suficientes para reconhecer pginas que no devem ser guardadas no cache e precisam ser buscadas novamente a cada requisio. Devemos entender que um servio de Proxy exige bastante memria e espao em disco rgido. O sistema deve ser dimensionado de forma adequada.
lidam diariamente com grandes acessos pblicos, que possuem o seu link Internet saturado com acessos a sites remotos que no esto relacionados finalidade da sua rede e a possibilidade de definir listas de bloqueios para restries destes acessos indevidos.
permitindo a criao de regras que restrinjam o trfego no horrio de expediente, e liberem nos horrios de menor demanda.
O Squid trabalha apenas com FTP, Gopher e HTTP. O Squid, no configura acesso a emails, ICQ, IRC, etc. Visto que no s funo do firewall trabalhar com o NAT (Network Address Translation), como tambm no faz sentido criar caches de e-mails pessoais e mensagens do ICQ.
CGI: Consiste numa importante tecnologia que permite gerar pginas dinmicas permitindo a um navegador passar parmetros para um programa alojado num servidor web.
Este um recurso bem interessante para controle pessoal de usurios, pois permite que voc crie ACLs individuais e gere logs de qualidade bem superior. Existem diversos mtodos de autenticao, sendo interessante averiguar exatamente o que ir precisar com base no plano de regras. Para controlar o acesso por usurios e grupos, podemos configurar o Squid como PDC. O (smb_auth) l o arquivo (\netlogon\proxyauth) que por padro e localizado no Linux, e em um dos controladores de domnio previamente informado. Se a leitura desse arquivo retorna um (allow) ou permitido , ento o acesso liberado. Caso contrrio se for um (deny) o acesso negado. Crie um arquivo chamado (proxyauth) no compartilhamento NETLOGON de seu PDC (d preferncia ao primrio). Esse arquivo deve conter unicamente a palavra (allow) e d permisso de leitura para os grupos e usurios que deseja permitir o acesso. O recurso de ACL externas muito til para um tratamento melhorado de algum recurso que no compreendido por ACLs normais. Uma ACL externa pode ser escrita em qualquer linguagem. Ela deve sempre retornar um valor de confirmao para o (stdout) caso a condio seja satisfeita, ou retornar um erro para o (stdout), caso ela no seja satisfeita.
Para facilitar a vida dos usurios e do administrator, conforme citado por (Reguly 2006), podemos criar um arquivo de configurao automtica que ser colocado nos Browsers dos clientes. Dessa forma todos tero seu Proxy reconfigurado dinamicamente em caso de mudanas, sem a necessidade de interveno em cada mquina. Esse arquivo deve ser acessvel via Web e, via de regra, chama-se (proxy.pac). A utilizao de sistemas de cache, como o Squid, tem se mostrado excelentes para aliviar certos sintomas, reduzindo o trfego na rede e, conseqentemente, a latncia da mesma ou seja a perda de banda. Toda a idia por trs 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 usurios da sua rede tentarem acessar um mesmo site ao mesmo tempo, somente uma das conexes realmente ir ser feita a esse site. Todas as outras 9 vo se aproveitar do primeiro acesso e utilizar a pgina j em memria. Isso um enorme ganho de desempenho para seu backbone local e para o backbone do ISP1 onde o site est armazenado e tambm para o servidor que hospeda o mesmo. Com todas essas configuraes habilitadas e funcionando corretamente possvel diminuir consideravelmente o fluxo de informaes na banda e controlar ao mximo o contedo acessado pelos usurios. 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 no agrega velocidade no est cumprindo o seu papel; Disponibilidade: De nada adianta um sistema veloz disponvel apenas 2 horas por dia, ou mesmo que precise de um reboot a cada 2 semanas. Em casos de grandes instalaes, ainda preciso ir mais a fundo, buscando uma altssima disponibilidade, como (Redundncia de servidores, backup, eliminao de ponto nico de falha); Transparncia ou Ostensividade: So conceitos especficos e que se adaptam a cada caso. Grandes instalaes, ISPs e empresas no preocupadas com que seus usurios vem ou fazem na Internet devem preferir a transparncia, onde o usurio desconhece ou no se sente afetado (exceto pelo ganho de velocidade) pela presena de um cache. Por outro lado, empresas com uma poltica de segurana mais rgida, rgos com informaes crticas, ou mesmo pais que queiram controlar o acesso de seus filhos a alguns sites, vo preferir a ostensividade;
1
ISP: servio de acesso internet, agregando a ele outros servios relacionados, tais como "e-mail", "hospedagem de sites" ou blogs, entre outros.
Capacidade de trabalhar com redes heterogneas: Ele capaz de trabalhar com diversos tipos de redes e no sendo necessrio estar exclusivamente amarrado a de um fabricante de Software ou de hardware, sendo assim ele se adapta a qualquer situao. Isso especialmente verdade quando no sabemos que tipo de plataforma iremos utilizar em nossa instalao; Simplicidade: Deixando um pouco de lado o usurio e focando no administrador, conforme citado por (Bastos 2006) preciso ter conscincia de que um sistema bom um sistema fcil de administrar. O mais rpido, mais disponvel e mais abrangente sistema de (caching) totalmente intil se somente uma pessoa no mundo souber lidar com ele. Cache hierrquico a extenso lgica do conceito de (caching). Um grupo de caches podem se beneficiar do compartilhamento de seus dados entre si de vrias formas. Isso facilmente explicvel quando pensamos em termos regionais. Como exemplo podemos citar o de uma empresa estabelecida em um prdio, pela qual os
usurios desta empresa resolvem enviar uma requisio de acesso a um determinado site, ento repassado esta requisio ao Proxy mais prximo, na qual baixa-se diretamente as informaes sem precisar sair para a Internet para baix-la. Fica fcil de visualizar que se todas as empresas interligassem localmente seus Proxies, todas sairiam ganhando. Na realidade, essa prtica entre pequenas empresas no existe. Mas quando falamos de grandes empresas e grandes backbone, cada 1 MB economizado com (caching) 1 MB ganho em outros servios. Alm 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 tambm com um conceito parecido com grupo de trabalho, onde todos os servidores se consultam mutuamente. Toda a comunicao entre os caches feita via ICP. O ICP foi desenvolvido como parte fundamental do projeto Harvest (Pai do Squid). Seu objetivo prover um mtodo rpido e eficiente de obter-se comunicao entre servidores cache. O ICP permite que um cache pergunte a outro se ele tem uma cpia vlida de um determinado objeto, aumentando a possibilidade de encontrar aquele objeto j (cacheado). Adicionalmente, o ICP permite que requisies trafeguem entre servidores filhos em uma estrutura de rvore. Alm do controle de cache, o ICP tambm gera indicaes do estado da rede. O no recebimento de uma resposta ICP normalmente indica que a rota est congestionada ou que outro Host no est ativo. Alm disso, a ordem de chegada de uma resposta ICP pode indicar quais hosts esto com uma distncia lgica menor ou com menos carga. As mensagens ICP so geralmente bem pequenas, com cerca de 66 bytes. Em uma estrutura hierrquica, normalmente tem-se mais trocas de mensagens ICP do que HTTP. Roteamento por domnio e outra caractersticas de configuraes do Squid pode favorecer muito no desempenho. A configurao 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 configurao (Reis, 2006). Sendo que o cache 4 ser o responsvel por todos os domnios que no sejam os 3 anteriores.
Ao escolher devemos sempre utilizar um hardware que permita atualizaes, especialmente em memria e armazenamento. Instalar servidores j com todos os bancos de memria usados ou no mximo de seus recursos sempre evitar. Pequenas instalaes dispensam disco rgido do tipo SCSI1, uma opo que j fica invivel em instalaes maiores. Conforme citao de Bastos (2006), ao utilizar RAID2, prefira o nvel 0 do que outros, visto que o mesmo feito para desempenho. interessante utilizar um disco rgido separado para os dados e para os logs do Squid. Se isso no for possvel, ao menos uma partio separada extremamente recomendada. Como normalmente, tanto os dados quanto os logs ficam abaixo do diretrio (/var), esse o ponto de montagem para essa partio. O desempenho das resolues DNS um ponto crtico e deve ser analisado como se segue. Em uma situao ideal, deveria existir um cache de DNS na mesma mquina ou em uma mquina muito prxima, para diminuir ao mximo o tempo de resoluo dos nomes. Em mltiplas rotas como em instalaes com o ISP pode ser vantajoso definir suas rotas manualmente. J em empresas mdias ou grandes que utilizam links de baixo custo, como ADSL 3, o balanceamento de carga nos links uma tima opo, conforme citado por Bastos (2006).
1
SCSI: A tecnologia criada para acelerar a taxa de transferncia de dados entre dispositivos de um computador, desde que tais perifricos sejam compatveis com o padro. 2 RAID: um meio de se criar uma unidade virtual composta por vrios discos individuais, com a finalidade de duplicao ou balanceamento.
3
3.4 - Tags
A seguir ser mostrado algumas tags de configurao do Squid. Alteraes bem feitas e pensadas podem trazer um grande ganho para a performance do cache, enquanto um erro de configurao pode impedir o Squid de trabalhar ou at mesmo remover muitas de suas funcionalidades. Estas configuraes so feitas editando o arquivo (squid.conf), localizado por padro no diretrio (/etc/squid/squid.conf). Http_port: Esta tag define qual porta ou portas do servio do Squid estar aberta, por padro definida a 3128; Cach_mem: Especifica o ideal a ser usado pelo Squid de memria, levar em considerao a quantidade de memria usada, por que ao ser setado valores extremamente altos os outros servios do sistema operacional sero prejudicados; Cache_swap_low: Este parmetro especificado para quando o tamanho do diretrio de Swap j estiver no mnimo, por padro costuma-se inserir o valor de 90; Cache_swap_high: Esta outra tag para especificar o tamanho do diretrio de Swap quando o mesmo j estiver no mximo, por padro costuma-se inserir o valor de 95.
TTL: Significa o nmero de mquinas que os pacotes podem demorar numa rede de computadores antes de serem descartados. 2 LRU: Algoritmo Adaptativo de Substituio de Pginas.
O modo (off-line) tambm nunca expira informaes de DNS que esteja no cache, e nunca renova pginas antigas. Isto no o que os usurios de (dial-up) e outros usurios com conexes intermitentes querem. Usando a configurao no modificada do Squid, (offline_mode on) que assinala ao Squid para nunca tentar uma validao, e (offline_mode off) que assinala uma operao normal.
3.6 - Vantagens
O Squid est continuadamente melhorando a sua performance, alm de adicionar novas funcionalidades e ter uma excelente estabilidade em condies extremas. Sua compatibilidade com vrias plataformas e a imensa quantidade de softwares para analisar logs, gerar relatrios, melhorar o desempenho, bem como a adico de segurana providos pela comunidade open source, combinados com ferramentas de administrao 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.
4.1 - Configurao
Esta idia surgiu da possibilidade de configurarmos o Squid de uma forma que o mesmo atinja o seu potencial mximo. Porm utilizando esta idia, iremos somente redefinir configuraes pr-existentes para que estas se encaixem no objetivo proposto. Nas pginas de anexos est o Squid proposto.
4.2 - HDparm
Aumenta a taxa de transferncia de dados do discos rgidos IDE com o HDparm. Como as maiorias das distribuies Linux sempre adaptam o sistema operacional para que ele esteja totalmente compatvel, algumas vezes deixado de lado o desempenho do hardware e neste caso que entra programas como o HDparm. A taxa de transferncia de dados quintuplica com o uso dos novos parmetros, se a compararmos com a configurao padro. O ganho de desempenho tende a ser muito grande mas o risco de perda de dados diretamente proporcional a ele. A melhor proteo 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.
Squid para com o navegador, ou seja, a capacidade de armazenar uma grande lista diretamente no disco rgido e no em memria como acontece normalmente.
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 intermediao entre o banco de dados e o Squid. Este programa desenvolvido utilizando a linguagem de programao Perl, o banco de dados que utilizamos para armazenar a nossa (black-list) o PostgreSQL. Dentro desta escolha inclumos como soluo requerida a implementao do HDparm e compilao do kernel e por ultimo inclumos nas listas de anexo o hardware ideal para a quantidade de usurios.
Vantagem sugerida que a (black-list - lista de URLs) no ser carregada na memria e sim no banco de dados, ento o Proxy Squid far toda a consulta de URLs diretamente em cima do banco de dados no sobrecarregando a memria do computador. Testamos o (front-end) feito em Perl com o banco de dados Postgres e seu funcionamento perfeito, foi constatado isso atravs de testes utilizando os seguintes parmetros tabela 3: 1 Inserimos dados no banco de dados; 2 Fizemos um select dos dados armazenados; 3 Exclumos os dados. Todo este processo feito atravs de um script Perl. O Perl utiliza uma biblioteca chamada DBI que facilita esta conexo com o banco de dados. Tabela 3 O passos efetuados (Reis, 2006).
O cdigo fonte segue abaixo com os devidos comentrios 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 cdigo do front-end (Reis, 2006). Na linha um colocado o caminho para o executvel da linguagem de programao Perl. A segunda linha chama a biblioteca DBI para fazer a conexo entre o banco de dados e a linguagem de programao, a linha trs referencia a conexo 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 varivel (res), logo o seu
contedo deve estar com 0 ou 1, 0 no 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 so responsveis 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 pgina requisitada pelo cliente (browser) ou liberado o seu acesso. As regras de liberao ou proibio no so efetuadas pelo (front-end), est definio responsabilidade do Squid com as suas ACLs. O programa citado acima ser usado para a busca no banco de dados. Quando a memria 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 rpida do que propriamente na memria. E foi isso que foi realizado.
parte da distribuio padro de Perl, faz com que a manipulao de formulrios HTML seja muito simples. Perl pode manipular dados encriptados, incluindo transaes de comrcio eletrnico. O pacote DBI do Perl faz com que a integrao com banco de dados Postgres seja muito simples.
informaes calcula os valores de desempenho do disco desconsiderando as informaes de dados do cache fornecendo uma medida eficiente do disco rgido que est sendo analisado. recomendvel efetuar vrios testes, a fim de calcular uma mdia, entretanto necessrio que desabilitemos vrios servios no computador para que o mesmo no fique sobrecarregado durante os testes prejudicando a preciso dos dados analisados. Aplicando o HDparm de forma criteriosa podemos aumentar em at cinco vezes o desempenho do disco rgido, algo ideal para aplicaes que necessitem de respostas altas. Algumas controladoras suportam 32 bits e esto rodando em 16 bits, este suporte pode ser configurado com a opo (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 transferncia de dados do disco rgido. Aplicando o comando (Hdparm d1 x66-u1 m16 cd /dev/hdaX), obtemos resultados que demonstram grande desempenho do disco rgido, atravs da opo (d1) ativamos o (flag) de utilizao de acesso direto memria (using-dma), a opo (x66) ativa o ULTRADMA, a opo (u1) desativa o mascaramento de outras interrupes (umaskirq). Podemos observar que a taxa de transferncia de dados quintuplica com o uso de novos parmetros comparado a configurao padro do computador. Depois de efetuar a configurao que aplica o desempenho do disco rgido atravs do HDparm devemos salvar a mesma para que a configurao no perca durante a reinicializao do sistema, basta utilizar um script de inicializao do sistema, chamado (rc.local) ou outro nome dependendo da distribuio para que toda a configurao fique de forma permanente, mas talvez em algumas controladoras, realizado um parmetro chamado (IDE reset) pode-se ainda perder a configurao. Aplicando a opo (k1) no comando evitamos que tal reset seja efetuado. A seguir apresentamos uma tabela feita com 3 discos rgidos, demonstramos os dados que possuem valores surpreendente tabela 6. Disco Rgido ST3400I5A Performance Veloc. Gravao 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
Com HDparm 378,11 MBps 36,54 MBps 686.9 MBps 24.77 MBps
SAMSUNG SV2001.4
Buffered disk reads 28.63 MBps 3.01 seg Tabela 6 Valores encontrados (Reis, 2006).
5.6.2 Kernel1
Para ganhar uma alta performance no sistema operacional Linux o ideal e compilar o Kernel (ncleo do sistema operacional, que faz a negociao entre Hardware e Software), com um kernel compilado somente com o bsico, ou seja, com suporte no kernel somente aos hardware que esto disponveis na mquina, a velocidade em processamento aproveitada somente para as aplicaes em uso, memria fica alocada somente para os aplicativos e servios que o sistema operacional precisa. Os procedimento abaixo foi citado por Gustavo Paes (2004), o foco o kernel 2.6 com Linux Slackware 9, porm seus conceitos podem ser levados para outras distribuies. Antes de
tudo, atualize o (Modutils/module-init-tools). necessario um conjunto novo de programas de gerenciamento de mdulos (modprobe, insmod, rmmod, etc), pois os que vm com o Slackware 9 no 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 diretrio 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 ncleo do Sistema Operacional ou, numa traduo literal, cerne.
NOTA: Os procedimentos a seguir devem ser executados pelo usurio 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 simblico "linux" apontando para a pasta do novo kernel: # ln -s /usr/src/linux-2.6.2 linux 4. Entre no diretrio /usr/src/linux: # cd /usr/scr/linux 5. Resete as configuraes do kernel: # make mrproper 6. Configure os mdulos do seu kernel: # make xconfig Existem duas formas de carregar os dispositivos no kernel, como mdulo (tecla M) e como parte do kernel (tecla Y). Opte por carregar como mdulo, isto acelera a velocidade, isso necessita usar o (/etc/rc.d/rc.local) descrito acima ou o (/etc/modprobe.conf) para carregar os mdulos automaticamente. Em LOADABLE MODULE SUPPORT, habilite o carregamento automtico de mdulos, ele vai tentar carregar as dependncias de um mdulo que voc esteja tentando carregar; Em PROCESSOR TYPE, escolha o processador, um kernel especfico para o processador bem mais rpido e estvel que um de 486. Nessa ponto, tenha em mos o manual da placa me, placa de vdeo, placa de TV, modem, etc; Em NETWORK SUPPORT, habilite os drivers da placa de rede. No use o (i2c) como parte do kernel, isso da futuros problemas na compilao do kernel. Em SOUND, desabilite a placa de som, recomendamos tambm 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. Recomendao de usar estes drivers como parte do kernel. Em ATA/ATAPI/M, habilite a emulao de SCSI, pois a maioria dos softwares de gravao 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 vdeo como mdulo (SIS, NVIDIA, ATI, etc), seno ficar difcil 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 tambm SELECT COMPILEDIN FONTE e marque as fontes 8x8, 8x16 e 4x6. Ative em LOGO CONFIGURATION todas as opes. 7. Limpe os arquivos temporrios e de instalao: # make clean 8. Compile a imagem do kernel: # make bzImage 9. Compile os mdulos do kernel (isso mesmo s um make): # make 10. Instale os mdulos 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 configurao do Kernel (Reis, 2006).
Captulo 6 - Concluso
Durante a pesquisa encontramos algumas aplicaes, conforme descrio anterior que foram implementadas, a fim de aperfeioar o desempenho do Squid. No entanto a nossa aplicao principal foi com o banco de dados PostgreSQL, na qual demonstrou que a sua implementao 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 relatrios) que implementou este mtodo com o banco de dados Mysql. Nossos testes demonstraram que com um hardware especifico, compilando o kernel somente com o mnimo e no compartilhando servios, adicionando o recurso de HDparm corretamente ao disco rgido, e com a implementao do uso do banco de dados o aumento na velocidade de transferncia 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 memria fsica do equipamento (RAM) e passou-se a utilizar o disco rgido (HD) utilizando para isto softwares como o Postgres para responder as requisies com muito mais velocidade. Com tudo isto que apresentamos neste trabalho, podemos concluir que ao utilizar estas ferramentas em conjunto (Front-end, HDparm, compilao de Kernel), podemos melhorar a performance do Squid sem alterar a estrutura do hardware. Assim sendo, com idias simples economizamos um investimento em hardware que era o nosso objetivo inicial.
Lista de anexos
Scripts utilizados para o front-end com Mysql Ligao Bases de Dados: #!/usr/bin/perl use DBI; #mdulo 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); Criao 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); Criao 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 Ligao: $?, $!, $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 criao 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 Quantidade de Usuarios Hardware Recomendado MotherBoard Memoria Processador Ate 100 HD IDE/SATA Placa de Rede Quantidade de Usuarios Hardware Recomendado MotherBoard Memoria Processador Ate 500 HD IDE/SATA/SCSI Placa de Rede Quantidade de Usuarios Hardware Recomendado MotherBoard Memoria Processador Ate 1000 HD IDE/SATA/SCSI Placa de Rede
Configuracoes Intel ou Via 1 Gb Intel Celeron D 2.8 Ghz 40 Gb Intel ou Realtek Configuracoes Intel ou Via 1 Gb Intel Pentium 4 HT 3 Ghz 80 Gb Intel ou Realtek Configuracoes Intel ou Via 2 Gb Intel Pentium 4 HT 3.4 Ghz 120 Gb Intel ou Realtek Configuracoes Intel com Chipset Intel 3 Gb Intel Pentium 4 HT 3.4 Ghz 80 Gb Intel ou Realtek
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 usurios /contas de e-mail: Celeron D 2.53Ghz com 1Gb de RAM, CDROM, HD de 40Gb, 2 placas de rede. (*) Com base no cenrio abaixo -50 usuarios logados simultneos link de 1Mbit -24 Mbytes de trfego de e-mails (Antivirus e AntiSpam) -72 hits hora no Webmail -840 Acesso hora POP
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 spekitru@yahoo.com.br 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 * * SQUID Web Proxy Cache * * 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" http://www.squid-cache.org/ * ---------------------------------------------------------Access Control * AUTHOR: Duane Wessels
#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; } if (mask != NULL) { /* 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 == NULL if called to decode a netmask */ /* This is not valid address */
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 #define SCAN_ACL2 #define SCAN_ACL3 #define SCAN_ACL4 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; 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; /* 255.255.255.255 */
} /* 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; }
{ 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; 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; /* ugly */
*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) return ERR_NONE; while (A) { L = A->acl_list; if (NULL == L) 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))) /* empty list should never happen, but in case */ /* empty list */
/* maex@space.net (05.09.96) * * * * * * */ 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; 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
/* 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, 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; } 0) ("aclParseDenyInfoLine: deny_info line contains 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; 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; /* defaults to non-negated */
/* * 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; } auth_match = memAllocate(MEM_ACL_PROXY_AUTH_MATCH); /* NOTREACHED */
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); }
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);
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) { rc = 1; else if (ntohl(A.s_addr) < ntohl(B.s_addr)) rc = -1; else rc = 0; } else { 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) /* range address check */ if (ntohl(A.s_addr) > ntohl(C.s_addr)) /* single address check */ if (ntohl(A.s_addr) > ntohl(B.s_addr))
{ 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; }
/* * From: * To: * Date: dale@server.ctam.bitmcnit.bryansk.su (Dale) wessels@nlanr.net 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 <luyer@ucs.uwa.edu.au>. * * */ #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> Original (BSD-specific) code no longer works. Solaris code by R. Gancarz <radekg@solaris.elektrownia-lagisza.com.pl>
#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; } 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) /* This is not valid address */
{ 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 - <luyer@ucs.uwa.edu.au> *********************************************************************** 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 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 "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 verses mais 2.4 at stable. 3 - Uso de parametros habilitados na hora da compilao. 4 - Uso de outros proxy's como alternativa para a soluo do problema. 5 - Hardware especializado. 6 - Melhora no algoritmo de ordenao e de busca. 7 - criao de uma tabela de indicao de hardware especifico para a quantidade de usuarios. 8 - cada requisio do browser considerada um GET
Referncias
ANDRADE, de abril de 2006. BASTOS, Eri Ramos. Configurando um Squid Ninja. Jociel. Instalando e configurando o Squid.
<http://geocities.yahoo.com.br/cesarakg/installing-configuring-squid.html>, Acesso em 15
CIPRIANO,
Luis
Alberto
Garcia.
Configurando
Oops.
<http://zipper.paco.net/~igor/oops.eng/features.html>, Acesso em 04 de maro de 2006. Deitel, Deitle; Mcphie, Nieto. Perl Como Programar. 3. ed. So Paulo. Bookman, 2005. Enciclopdia 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. So Paulo. Novatec, 2003. JNIOR, Walter Flvio em Pimenta. MPI. Hiperquicksort: Uma Anlise Prtica em 14 com de
<http://www.comp.ufla.br/monografias/ano2002/Hiper
quicksort_uma_analise_pratica_com_implementacao_em_MP.pdf>,Acesso
Stfano.
Guia
Sobre
Squid/Proxy
Transparente.
<http://squid.linuxit.com.br/download/squid/antigos/guiasquid-txt-1.2.txt>. Acesso em 11 de
Oliveira, Alvaro Mendes de.Squid Plus com AD, redirector, controle de banda e relatrios.<http://www.vivaolinux.com.br/artigos/verArtigo.php?codigo=4716> .Acesso em
23 de setembro de 2006. Paes, Gustavo. Instalando e configurando os mdulos 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. skin=print1>, Acesso em 15 abril de 2006. REIS, Cristiano Fernandes dos reis. Desenho de rede ideal de um servio Proxy. So Paulo. 2006. e configurando o
.<http://www.sistemasabertos.com.br/twiki/bin/viewpub/Pub/ArtigoServidorProxy?
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. So 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.
Wolfer, Thomas. Aumente a taxa de transferencia de dados de seus discos IDE com o hdparm. Linux Magazine. So Paulo: Setembro, ano 1, n 2, set 2004. pg. 36.
ftp://www.delegate.org/pub/DeleGate/Manual.htm#DESCRIPTION **http://lists.debian.org/debian-l10n-portuguese/2001/10/msg00052.html ---------------------------////////////////////-------------------------------------------------------------------------------------////////////////////----------------------------------------------------------Data: 02/05/2006 **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 Hora: 17:13:00 **http://www.inf.ufes.br/~proinfo/aulas_via_chat/Setembro-01/turma2_0109.htm
FTP (File Transfer Protocol - Protocolo de Transferncia de Arquivos): uma forma bastante rpida e verstil de transferir arquivos, sendo uma das mais usadas na internet. Gateway: uma mquina intermediria geralmente destinada a interligar redes, separar domnios de coliso, ou mesmo traduzir protocolos. Exemplos de gateway podem ser os routers (ou roteadores) e firewalls, j que ambos servem de intermedirios entre o utilizador e a rede. Um Proxy tambm pode ser interpretado como um gateway (embora em outro nvel, aquele da camada em que opera), j que serve de intermedirio tambm. Gopher: um protocolo de redes de computadores que foi desenhado para indexar repositrios de documentos na Internet. Host: qualquer mquina 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 Formatao de Hipertexto): Trata-se de uma linguagem de marcao utilizada para produzir pginas na Internet. De modo geral so documentos de texto escritos em cdigos que podem ser interpretados pelos browsers para exibir as pginas da World Wide Web. HTTP (HyperText Transfer Protocol - Protocolo de Transferncia de Hipertexto): um protocolo da camada de "Aplicao" do modelo OSI, utilizado para transferncia 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 caractersticas so: geralmente este protocolo, utiliza a porta 80 e usado para a comunicao de "sites". ICP (Infra-estrutura de Chaves Pblicas): Uma Infra-Estrutura de Chaves Pblicas um rgo ou inciativa pblica ou privada para a organizao de uma estrutura de emisso de chaves pblicas, baseando-se no princpio da terceira parte confivel, oferecendo uma mediao de acreditao e confiana em transaes entre partes que utilizam certificados digitais, bem como se responsabilizando pela emisso de tais certificados, assumindo-se ento como a parte confivel destas transaes. A infra-estrutura de chaves pblicas do Brasil a Infra-Estrutura de Chaves Pblicas Brasileira, ou ICP-Brasil. ICQ: um programa de comunicao instantnea pela Internet que foi o mais popular durante anos. IMAP (Internet Message Access Protocol): um protocolo de gerenciamento de correio eletrnico superior em recursos ao POP3 - protocolo que a maioria dos provedores oferece aos seus assinantes. A ltima verso 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 mquinas em rede para encaminhamento dos dados. ISP (Internet Service Provider): Oferece principalmente servio de acesso internet, agregando a ele outros servios relacionados, tais como "e-mail", "hospedagem de sites" ou blogs, entre outros. Kernel: entendido como o ncleo do Sistema Operacional ou, numa traduo literal, cerne. Ele representa a camada mais baixa de interface com o Hardware, sendo responsvel por gerenciar os recursos do sistema computacional como um todo. no kernel que esto definidas funes para operao com perifricos (mouse, discos, impressoras, interface serial/interface paralela), gerenciamento de memria, entre outros. Resumidamente, o kernel um conjunto de programas que fornece para os programas de usurio (aplicativos) uma interface para utilizar os recursos do sistema. Link: uma referncia num documento em hipertexto a outro documento ou a outro recurso. Login: um conjunto de caracteres solicitado para os usurios que por algum motivo necessitam acessar algum sistema computacional. Geralmente os sistemas computacionais solicitam um login e uma senha para a liberao 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 eletrnico.
NAT (Network Address Translation): Tambm conhecido como masquerading uma tcnica que consiste em reescrever os endereos 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 pblica). NFS (Network File System): um modelo de sistema de arquivos, que tem como funo centralizar arquivos em um servidor, formando assim um diretrio virtual. NNTP (Network News Transfer Protocol): um protocolo da internet para grupos de discusso da chamada usenet. OSI (Open Systems Interconnection): um conjunto de padres ISO relativo comunicao de dados. POP (Post Office Protocol (POP3)): um protocolo utilizado no acesso remoto a uma caixa de correio eletrnico. RAID (Redundant Array of Independent Disks - Conjunto Redundante de Discos): um meio de se criar uma unidade virtual composta por vrios discos individuais, com a finalidade de duplicao (redundncia, recuperao de falhas) ou balanceamento (operaes I/O em paralelo). SCSI (Small Computer System Interface): A tecnologia SCSI foi criada para acelerar a taxa de transferncia de dados entre dispositivos de um computador, desde que tais perifricos sejam compatveis com o padro. SMTP (Simple Mail Transfer Protocol): o padro de fato para envio de e-mail atravs da Internet. SSL (Secure Sockets Layer): um protocolo criptogrfico que provem comunicao segura na Internet para coisas como e-mail, navegao por pginas, e outros tipos de transferncia de dados. Tag: So estruturas de linguagem de marcao que consistem em breves instrues, tendo uma marca de incio e outra de fim. TCP (Transmission Control Protocol): um dos protocolos sob os quais assenta o ncleo 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 so enviados de forma correta, na seqncia apropriada e sem erros, pela rede. Telnet: um protocolo cliente-servidor de comunicaes usado para permitir a comunicao entre computadores ligados numa rede, baseado em TCP. TTL (Time to Live): Significa o nmero de mquinas que os pacotes podem demorar numa rede de computadores antes de serem descartados (mx. 255). UDP: D s aplicaes acesso direto ao servio de entrega de datagramas, como o servio de entrega que o IP d. URL (Universal Resource Locator - Localizador Universal de Recursos): o endereo de um recurso, disponvel em uma rede; seja a Internet, ou uma rede corporativa, uma intranet. WEB: uma rede de computadores na Internet que fornece informao em forma de hipertexto.