Mostrando entradas con la etiqueta Seguridad Informática. Mostrar todas las entradas
Mostrando entradas con la etiqueta Seguridad Informática. Mostrar todas las entradas

miércoles, 14 de marzo de 2018

FTP Pasivo con Iptables

Que sí, es penoso que a estas alturas del siglo se siga configurando FTP como una especie de solución para almacenamiento.

El objetivo de este post es resolver cierto problema con los permisos que se configuran en nuestro firewall con iptables para el FTP pasivo. Que básicamente no funcionan.

El FTP pasivo se beneficia de las reglas para tráfico "de respuesta" que identificamos mediante el módulo conntrack
-m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
En nuestra cadena FORWARD de FILTER al hablar de nuestro firewall; esto, una vez que hayamos cargado el módulo ip_conntrack_ftp y, hasta donde entiendo, nf_nat_ftp.
modprobe nf_nat_ftp
modprobe ip_conntrack_ftp
Para hacerlo permanente:
sed -i '$a ip_conntrack_ftp\nnf_nat_ftp ' /etc/modules
Aún con eso sigue sin funcionar. La solución la encontré en Iptables to allow incoming FTP: Debe configurarse el kernel con net.netfilter.nf_conntrack_helper=1.  Yo soy más de la idea de ponerlo directamente en /etc/sysctl.conf, pero en realidad puede ir al gusto:
sed -i '$a net.netfilter.nf_conntrack_helper=1' /etc/sysctl.conf

martes, 9 de junio de 2015

Cbpolicyd en Zimbra

Un tux-cartero-censor es la mejor idea para un logo
 Parafraseando la descripción que ellos mismos dicen acerca de su desarrollo:
PolicyD v2 (Nombre en clave “cluebringer”, de cuya contracción queda cbpolicyd), es un servidor de políticas multiplataforma para los servidores MTA más populares. Este servicio de políticas está diseñado principalmente para entornos de hosting de correo a gran escala. El principal objetivo es implementar tantas características de combate al spam y de sanitización de correo como sea posible, mientras al mismo tiempo se mantiene la portabilidad, estabilidad y rendimiento requerido para la crítica misión de hosting de correo. La mayoría de ideas y métodos implementados en cbpolicyd derivan de Policyd v1, así como de la larga participación de los autores en la industria del hosting de correo a gran escala.
Si bien pueden complicarse las reglas con el fin de usar todas las características posibles (Verificación de SPF y HELO, por mencionar algunas), es necesario entender que la comprobación de cbpolicyd ocurre dentro de los procesos de postfix, por lo que puede reducir el tiempo de respuesta frente al usuario.
Las demás características de cbpolicyd pueden implementarse dentro de la configuración anti-spam posterior, siendo de hecho un poco menos restrictivas y más flexibles.

Por ahora, usaremos cbpolicyd para definir políticas de volumen de correo por remitente, esto es, cuántos correos puede un mismo remitente enviar por unidad de tiempo, una característica que le dará un perfil bastante profesional a nuestro servicio de correo electrónico.

La configuración por defecto de zimbra (Bastante sencilla de poner en marcha, dicho sea de paso) tiene un problema de rendimiento inherente al hecho de usar Sqlite como backend, así que en su momento hemos de cambiar la configuración para que use una base de datos que hemos de configurar en el servidor mysql que zimbra ha instalado por defecto.
No sé de otros casos, pero un servidor mediano con más de 5,000 cuentas de correo se verá seriamente afectado en algunas horas del día si no se hace este cambio.

Comprobamos que sqlite esté instalado en el servidor, caso contrario, tendremos un pequeño error al arrancar el servicio por primera vez:

rpm -qa | grep sqlite
sqlite-3.6.20-1.el6.x86_64

Los siguientes son los script para creación de base de datos y de nuestras reglas, que hemos de usar más adelante:

~/backup/cbpolicyd/cbpolicyd.mysql.sql
-- -----------------------------------------------------
-- Schema cbpolicyd
-- -----------------------------------------------------
CREATE SCHEMA IF NOT EXISTS `cbpolicyd` DEFAULT CHARACTER SET latin1 ;
USE `cbpolicyd` ;

-- -----------------------------------------------------
-- Table `cbpolicyd`.`policies`
-- -----------------------------------------------------
DROP TABLE IF EXISTS `cbpolicyd`.`policies` ;

CREATE TABLE IF NOT EXISTS `cbpolicyd`.`policies` (
  `ID` INT(11) NOT NULL AUTO_INCREMENT,
  `Name` VARCHAR(255) NOT NULL,
  `Priority` SMALLINT(6) NOT NULL,
  `Description` TEXT NULL DEFAULT NULL,
  `Disabled` SMALLINT(6) NOT NULL DEFAULT '0',
  PRIMARY KEY (`ID`))
ENGINE = InnoDB
DEFAULT CHARACTER SET = latin1;


-- -----------------------------------------------------
-- Table `cbpolicyd`.`access_control`
-- -----------------------------------------------------
DROP TABLE IF EXISTS `cbpolicyd`.`access_control` ;

CREATE TABLE IF NOT EXISTS `cbpolicyd`.`access_control` (
  `ID` INT(11) NOT NULL AUTO_INCREMENT,
  `PolicyID` INT(11) NULL DEFAULT NULL,
  `Name` VARCHAR(255) NOT NULL,
  `Verdict` VARCHAR(255) NULL DEFAULT NULL,
  `Data` TEXT NULL DEFAULT NULL,
  `Comment` VARCHAR(1024) NULL DEFAULT NULL,
  `Disabled` SMALLINT(6) NOT NULL DEFAULT '0',
  PRIMARY KEY (`ID`),
  INDEX `PolicyID` (`PolicyID` ASC),
  CONSTRAINT `access_control_ibfk_1`
    FOREIGN KEY (`PolicyID`)
    REFERENCES `cbpolicyd`.`policies` (`ID`))
ENGINE = InnoDB
DEFAULT CHARACTER SET = latin1;


-- -----------------------------------------------------
-- Table `cbpolicyd`.`checkhelo`
-- -----------------------------------------------------
DROP TABLE IF EXISTS `cbpolicyd`.`checkhelo` ;

CREATE TABLE IF NOT EXISTS `cbpolicyd`.`checkhelo` (
  `ID` INT(11) NOT NULL AUTO_INCREMENT,
  `PolicyID` INT(11) NULL DEFAULT NULL,
  `Name` VARCHAR(255) NOT NULL,
  `UseBlacklist` SMALLINT(6) NULL DEFAULT NULL,
  `BlacklistPeriod` BIGINT(20) UNSIGNED NULL DEFAULT NULL,
  `UseHRP` SMALLINT(6) NULL DEFAULT NULL,
  `HRPPeriod` BIGINT(20) UNSIGNED NULL DEFAULT NULL,
  `HRPLimit` BIGINT(20) UNSIGNED NULL DEFAULT NULL,
  `RejectInvalid` SMALLINT(6) NULL DEFAULT NULL,
  `RejectIP` SMALLINT(6) NULL DEFAULT NULL,
  `RejectUnresolvable` SMALLINT(6) NULL DEFAULT NULL,
  `Comment` VARCHAR(1024) NULL DEFAULT NULL,
  `Disabled` SMALLINT(6) NOT NULL DEFAULT '0',
  PRIMARY KEY (`ID`),
  INDEX `PolicyID` (`PolicyID` ASC),
  CONSTRAINT `checkhelo_ibfk_1`
    FOREIGN KEY (`PolicyID`)
    REFERENCES `cbpolicyd`.`policies` (`ID`))
ENGINE = InnoDB
DEFAULT CHARACTER SET = latin1;


-- -----------------------------------------------------
-- Table `cbpolicyd`.`checkhelo_blacklist`
-- -----------------------------------------------------
DROP TABLE IF EXISTS `cbpolicyd`.`checkhelo_blacklist` ;

CREATE TABLE IF NOT EXISTS `cbpolicyd`.`checkhelo_blacklist` (
  `ID` INT(11) NOT NULL AUTO_INCREMENT,
  `Helo` VARCHAR(255) NOT NULL,
  `Comment` VARCHAR(1024) NULL DEFAULT NULL,
  `Disabled` SMALLINT(6) NOT NULL DEFAULT '0',
  PRIMARY KEY (`ID`),
  UNIQUE INDEX `Helo` (`Helo` ASC))
ENGINE = InnoDB
DEFAULT CHARACTER SET = latin1;


-- -----------------------------------------------------
-- Table `cbpolicyd`.`checkhelo_tracking`
-- -----------------------------------------------------
DROP TABLE IF EXISTS `cbpolicyd`.`checkhelo_tracking` ;

CREATE TABLE IF NOT EXISTS `cbpolicyd`.`checkhelo_tracking` (
  `Address` VARCHAR(64) NOT NULL,
  `Helo` VARCHAR(255) NOT NULL,
  `LastUpdate` BIGINT(20) UNSIGNED NOT NULL,
  UNIQUE INDEX `Address` (`Address` ASC, `Helo` ASC),
  INDEX `checkhelo_tracking_idx1` (`LastUpdate` ASC))
ENGINE = InnoDB
DEFAULT CHARACTER SET = latin1;


-- -----------------------------------------------------
-- Table `cbpolicyd`.`checkhelo_whitelist`
-- -----------------------------------------------------
DROP TABLE IF EXISTS `cbpolicyd`.`checkhelo_whitelist` ;

CREATE TABLE IF NOT EXISTS `cbpolicyd`.`checkhelo_whitelist` (
  `ID` INT(11) NOT NULL AUTO_INCREMENT,
  `Source` VARCHAR(512) NOT NULL,
  `Comment` VARCHAR(1024) NULL DEFAULT NULL,
  `Disabled` SMALLINT(6) NOT NULL DEFAULT '0',
  PRIMARY KEY (`ID`),
  UNIQUE INDEX `Source` (`Source` ASC))
ENGINE = InnoDB
DEFAULT CHARACTER SET = latin1;


-- -----------------------------------------------------
-- Table `cbpolicyd`.`checkspf`
-- -----------------------------------------------------
DROP TABLE IF EXISTS `cbpolicyd`.`checkspf` ;

CREATE TABLE IF NOT EXISTS `cbpolicyd`.`checkspf` (
  `ID` INT(11) NOT NULL AUTO_INCREMENT,
  `PolicyID` INT(11) NULL DEFAULT NULL,
  `Name` VARCHAR(255) NOT NULL,
  `UseSPF` SMALLINT(6) NULL DEFAULT NULL,
  `RejectFailedSPF` SMALLINT(6) NULL DEFAULT NULL,
  `AddSPFHeader` SMALLINT(6) NULL DEFAULT NULL,
  `Comment` VARCHAR(1024) NULL DEFAULT NULL,
  `Disabled` SMALLINT(6) NOT NULL DEFAULT '0',
  PRIMARY KEY (`ID`),
  INDEX `PolicyID` (`PolicyID` ASC),
  CONSTRAINT `checkspf_ibfk_1`
    FOREIGN KEY (`PolicyID`)
    REFERENCES `cbpolicyd`.`policies` (`ID`))
ENGINE = InnoDB
DEFAULT CHARACTER SET = latin1;


-- -----------------------------------------------------
-- Table `cbpolicyd`.`greylisting`
-- -----------------------------------------------------
DROP TABLE IF EXISTS `cbpolicyd`.`greylisting` ;

CREATE TABLE IF NOT EXISTS `cbpolicyd`.`greylisting` (
  `ID` INT(11) NOT NULL AUTO_INCREMENT,
  `PolicyID` INT(11) NULL DEFAULT NULL,
  `Name` VARCHAR(255) NOT NULL,
  `UseGreylisting` SMALLINT(6) NULL DEFAULT NULL,
  `GreylistPeriod` BIGINT(20) UNSIGNED NULL DEFAULT NULL,
  `Track` VARCHAR(255) NOT NULL,
  `GreylistAuthValidity` BIGINT(20) UNSIGNED NULL DEFAULT NULL,
  `GreylistUnAuthValidity` BIGINT(20) UNSIGNED NULL DEFAULT NULL,
  `UseAutoWhitelist` SMALLINT(6) NULL DEFAULT NULL,
  `AutoWhitelistPeriod` BIGINT(20) UNSIGNED NULL DEFAULT NULL,
  `AutoWhitelistCount` BIGINT(20) UNSIGNED NULL DEFAULT NULL,
  `AutoWhitelistPercentage` BIGINT(20) UNSIGNED NULL DEFAULT NULL,
  `UseAutoBlacklist` SMALLINT(6) NULL DEFAULT NULL,
  `AutoBlacklistPeriod` BIGINT(20) UNSIGNED NULL DEFAULT NULL,
  `AutoBlacklistCount` BIGINT(20) UNSIGNED NULL DEFAULT NULL,
  `AutoBlacklistPercentage` BIGINT(20) UNSIGNED NULL DEFAULT NULL,
  `Comment` VARCHAR(1024) NULL DEFAULT NULL,
  `Disabled` SMALLINT(6) NOT NULL DEFAULT '0',
  PRIMARY KEY (`ID`),
  INDEX `PolicyID` (`PolicyID` ASC),
  CONSTRAINT `greylisting_ibfk_1`
    FOREIGN KEY (`PolicyID`)
    REFERENCES `cbpolicyd`.`policies` (`ID`))
ENGINE = InnoDB
DEFAULT CHARACTER SET = latin1;


-- -----------------------------------------------------
-- Table `cbpolicyd`.`greylisting_autoblacklist`
-- -----------------------------------------------------
DROP TABLE IF EXISTS `cbpolicyd`.`greylisting_autoblacklist` ;

CREATE TABLE IF NOT EXISTS `cbpolicyd`.`greylisting_autoblacklist` (
  `ID` INT(11) NOT NULL AUTO_INCREMENT,
  `TrackKey` VARCHAR(512) NOT NULL,
  `Added` BIGINT(20) UNSIGNED NOT NULL,
  `Comment` VARCHAR(1024) NULL DEFAULT NULL,
  PRIMARY KEY (`ID`),
  UNIQUE INDEX `TrackKey` (`TrackKey` ASC))
ENGINE = InnoDB
DEFAULT CHARACTER SET = latin1;


-- -----------------------------------------------------
-- Table `cbpolicyd`.`greylisting_autowhitelist`
-- -----------------------------------------------------
DROP TABLE IF EXISTS `cbpolicyd`.`greylisting_autowhitelist` ;

CREATE TABLE IF NOT EXISTS `cbpolicyd`.`greylisting_autowhitelist` (
  `ID` INT(11) NOT NULL AUTO_INCREMENT,
  `TrackKey` VARCHAR(512) NOT NULL,
  `Added` BIGINT(20) UNSIGNED NOT NULL,
  `LastSeen` BIGINT(20) UNSIGNED NOT NULL,
  `Comment` VARCHAR(1024) NULL DEFAULT NULL,
  PRIMARY KEY (`ID`),
  UNIQUE INDEX `TrackKey` (`TrackKey` ASC))
ENGINE = InnoDB
DEFAULT CHARACTER SET = latin1;


-- -----------------------------------------------------
-- Table `cbpolicyd`.`greylisting_tracking`
-- -----------------------------------------------------
DROP TABLE IF EXISTS `cbpolicyd`.`greylisting_tracking` ;

CREATE TABLE IF NOT EXISTS `cbpolicyd`.`greylisting_tracking` (
  `TrackKey` VARCHAR(512) NOT NULL,
  `Sender` VARCHAR(255) NOT NULL,
  `Recipient` VARCHAR(255) NOT NULL,
  `FirstSeen` BIGINT(20) UNSIGNED NOT NULL,
  `LastUpdate` BIGINT(20) UNSIGNED NOT NULL,
  `Tries` BIGINT(20) UNSIGNED NOT NULL,
  `Count` BIGINT(20) UNSIGNED NOT NULL,
  UNIQUE INDEX `TrackKey` (`TrackKey` ASC, `Sender` ASC, `Recipient` ASC),
  INDEX `greylisting_tracking_idx1` (`LastUpdate` ASC, `Count` ASC))
ENGINE = InnoDB
DEFAULT CHARACTER SET = latin1;


-- -----------------------------------------------------
-- Table `cbpolicyd`.`greylisting_whitelist`
-- -----------------------------------------------------
DROP TABLE IF EXISTS `cbpolicyd`.`greylisting_whitelist` ;

CREATE TABLE IF NOT EXISTS `cbpolicyd`.`greylisting_whitelist` (
  `ID` INT(11) NOT NULL AUTO_INCREMENT,
  `Source` VARCHAR(255) NOT NULL,
  `Comment` VARCHAR(1024) NULL DEFAULT NULL,
  `Disabled` SMALLINT(6) NOT NULL DEFAULT '0',
  PRIMARY KEY (`ID`),
  UNIQUE INDEX `Source` (`Source` ASC))
ENGINE = InnoDB
DEFAULT CHARACTER SET = latin1;


-- -----------------------------------------------------
-- Table `cbpolicyd`.`policy_groups`
-- -----------------------------------------------------
DROP TABLE IF EXISTS `cbpolicyd`.`policy_groups` ;

CREATE TABLE IF NOT EXISTS `cbpolicyd`.`policy_groups` (
  `ID` INT(11) NOT NULL AUTO_INCREMENT,
  `Name` VARCHAR(255) NOT NULL,
  `Disabled` SMALLINT(6) NOT NULL DEFAULT '0',
  `Comment` VARCHAR(1024) NULL DEFAULT NULL,
  PRIMARY KEY (`ID`),
  UNIQUE INDEX `Name` (`Name` ASC))
ENGINE = InnoDB
DEFAULT CHARACTER SET = latin1;


-- -----------------------------------------------------
-- Table `cbpolicyd`.`policy_group_members`
-- -----------------------------------------------------
DROP TABLE IF EXISTS `cbpolicyd`.`policy_group_members` ;

CREATE TABLE IF NOT EXISTS `cbpolicyd`.`policy_group_members` (
  `ID` INT(11) NOT NULL AUTO_INCREMENT,
  `PolicyGroupID` INT(11) NULL DEFAULT NULL,
  `Member` VARCHAR(255) NOT NULL,
  `Disabled` SMALLINT(6) NOT NULL DEFAULT '0',
  `Comment` VARCHAR(1024) NULL DEFAULT NULL,
  PRIMARY KEY (`ID`),
  INDEX `PolicyGroupID` (`PolicyGroupID` ASC),
  CONSTRAINT `policy_group_members_ibfk_1`
    FOREIGN KEY (`PolicyGroupID`)
    REFERENCES `cbpolicyd`.`policy_groups` (`ID`))
ENGINE = InnoDB
DEFAULT CHARACTER SET = latin1;


-- -----------------------------------------------------
-- Table `cbpolicyd`.`policy_members`
-- -----------------------------------------------------
DROP TABLE IF EXISTS `cbpolicyd`.`policy_members` ;

CREATE TABLE IF NOT EXISTS `cbpolicyd`.`policy_members` (
  `ID` INT(11) NOT NULL AUTO_INCREMENT,
  `PolicyID` INT(11) NULL DEFAULT NULL,
  `Source` TEXT NULL DEFAULT NULL,
  `Destination` TEXT NULL DEFAULT NULL,
  `Comment` VARCHAR(1024) NULL DEFAULT NULL,
  `Disabled` SMALLINT(6) NOT NULL DEFAULT '0',
  PRIMARY KEY (`ID`),
  INDEX `PolicyID` (`PolicyID` ASC),
  CONSTRAINT `policy_members_ibfk_1`
    FOREIGN KEY (`PolicyID`)
    REFERENCES `cbpolicyd`.`policies` (`ID`))
ENGINE = InnoDB
DEFAULT CHARACTER SET = latin1;


-- -----------------------------------------------------
-- Table `cbpolicyd`.`quotas`
-- -----------------------------------------------------
DROP TABLE IF EXISTS `cbpolicyd`.`quotas` ;

CREATE TABLE IF NOT EXISTS `cbpolicyd`.`quotas` (
  `ID` INT(11) NOT NULL AUTO_INCREMENT,
  `PolicyID` INT(11) NULL DEFAULT NULL,
  `Name` VARCHAR(255) NOT NULL,
  `Track` VARCHAR(255) NOT NULL,
  `Period` BIGINT(20) UNSIGNED NULL DEFAULT NULL,
  `Verdict` VARCHAR(255) NULL DEFAULT NULL,
  `Data` TEXT NULL DEFAULT NULL,
  `LastQuota` SMALLINT(6) NOT NULL DEFAULT '0',
  `Comment` VARCHAR(1024) NULL DEFAULT NULL,
  `Disabled` SMALLINT(6) NOT NULL DEFAULT '0',
  PRIMARY KEY (`ID`),
  INDEX `PolicyID` (`PolicyID` ASC),
  CONSTRAINT `quotas_ibfk_1`
    FOREIGN KEY (`PolicyID`)
    REFERENCES `cbpolicyd`.`policies` (`ID`))
ENGINE = InnoDB
DEFAULT CHARACTER SET = latin1;


-- -----------------------------------------------------
-- Table `cbpolicyd`.`quotas_limits`
-- -----------------------------------------------------
DROP TABLE IF EXISTS `cbpolicyd`.`quotas_limits` ;

CREATE TABLE IF NOT EXISTS `cbpolicyd`.`quotas_limits` (
  `ID` INT(11) NOT NULL AUTO_INCREMENT,
  `QuotasID` INT(11) NULL DEFAULT NULL,
  `Type` VARCHAR(255) NULL DEFAULT NULL,
  `CounterLimit` BIGINT(20) UNSIGNED NULL DEFAULT NULL,
  `Comment` VARCHAR(1024) NULL DEFAULT NULL,
  `Disabled` SMALLINT(6) NOT NULL DEFAULT '0',
  PRIMARY KEY (`ID`),
  INDEX `QuotasID` (`QuotasID` ASC),
  CONSTRAINT `quotas_limits_ibfk_1`
    FOREIGN KEY (`QuotasID`)
    REFERENCES `cbpolicyd`.`quotas` (`ID`))
ENGINE = InnoDB
DEFAULT CHARACTER SET = latin1;


-- -----------------------------------------------------
-- Table `cbpolicyd`.`quotas_tracking`
-- -----------------------------------------------------
DROP TABLE IF EXISTS `cbpolicyd`.`quotas_tracking` ;

CREATE TABLE IF NOT EXISTS `cbpolicyd`.`quotas_tracking` (
  `QuotasLimitsID` INT(11) NULL DEFAULT NULL,
  `TrackKey` VARCHAR(512) NULL DEFAULT NULL,
  `LastUpdate` BIGINT(20) UNSIGNED NULL DEFAULT NULL,
  `Counter` DECIMAL(10,4) NULL DEFAULT NULL,
  UNIQUE INDEX `QuotasLimitsID` (`QuotasLimitsID` ASC, `TrackKey` ASC),
  INDEX `quotas_tracking_idx1` (`LastUpdate` ASC),
  CONSTRAINT `quotas_tracking_ibfk_1`
    FOREIGN KEY (`QuotasLimitsID`)
    REFERENCES `cbpolicyd`.`quotas_limits` (`ID`))
ENGINE = InnoDB
DEFAULT CHARACTER SET = latin1;


-- -----------------------------------------------------
-- Table `cbpolicyd`.`session_tracking`
-- -----------------------------------------------------
DROP TABLE IF EXISTS `cbpolicyd`.`session_tracking` ;

CREATE TABLE IF NOT EXISTS `cbpolicyd`.`session_tracking` (
  `Instance` VARCHAR(255) NULL DEFAULT NULL,
  `QueueID` VARCHAR(255) NULL DEFAULT NULL,
  `UnixTimestamp` BIGINT(20) NOT NULL,
  `ClientAddress` VARCHAR(64) NULL DEFAULT NULL,
  `ClientName` VARCHAR(255) NULL DEFAULT NULL,
  `ClientReverseName` VARCHAR(255) NULL DEFAULT NULL,
  `Protocol` VARCHAR(255) NULL DEFAULT NULL,
  `EncryptionProtocol` VARCHAR(255) NULL DEFAULT NULL,
  `EncryptionCipher` VARCHAR(255) NULL DEFAULT NULL,
  `EncryptionKeySize` VARCHAR(255) NULL DEFAULT NULL,
  `SASLMethod` VARCHAR(255) NULL DEFAULT NULL,
  `SASLSender` VARCHAR(255) NULL DEFAULT NULL,
  `SASLUsername` VARCHAR(255) NULL DEFAULT NULL,
  `Helo` VARCHAR(255) NULL DEFAULT NULL,
  `Sender` VARCHAR(255) NULL DEFAULT NULL,
  `Size` BIGINT(20) UNSIGNED NULL DEFAULT NULL,
  `RecipientData` TEXT NULL DEFAULT NULL,
  UNIQUE INDEX `Instance` (`Instance` ASC),
  INDEX `session_tracking_idx1` (`QueueID` ASC, `ClientAddress` ASC, `Sender` ASC),
  INDEX `session_tracking_idx2` (`UnixTimestamp` ASC))
ENGINE = InnoDB
DEFAULT CHARACTER SET = latin1;

El siguiente ejemplo esta recortado a próposito, pero supongo que podría ser bastante ilustrativo sobre la forma de crear las reglas. En todo caso, encontrar una la forma correcta de hacer estas reglas parece ser más arte que ciencia, en cuanto la documentación disponible me ha parecido extrañamente escasa

~/backup/cbpolicyd/dominio.mysql.sql

use cbpolicyd;

/* Creamos los grupos que hemos de usar posteriormente en la tabla policy_members */
INSERT INTO policy_groups (Name) values('MAILSERVER');
/* Asignamos algunos miembros a los grupos */
INSERT INTO policy_group_members (PolicyGroupID,Member, Comment) VALUES (1,'10.10.20.2/24', 'MailServer');
INSERT INTO policy_group_members (PolicyGroupID,Member, Comment) VALUES (1,'190.86.170.10/24', 'IP Pública');

INSERT INTO policy_groups (Name) values('MIRED');
INSERT INTO policy_group_members (PolicyGroupID,Member, Comment) VALUES (2,'192.168.20.0/24', 'Redes LAN');
INSERT INTO policy_group_members (PolicyGroupID,Member, Comment) VALUES (2,'10.10.20.0/24', 'DMZ');

INSERT INTO policy_groups (Name) values("DOMINIOS");
INSERT INTO policy_group_members (PolicyGroupID,Member, Comment) VALUES (3,'@dominio.com', 'Dominio Principal');

/* Creamos las politicas en tabla policies. Cada politica debe tener al menos un miembro definido en policy_members */
INSERT INTO policies (Name,Priority,Description) VALUES ('PoliticaMailServer',0,'Primer politica con Mail Server');
/* Asignamos miembros haciendo politicas que definan origen y destino  */
INSERT INTO policy_members (PolicyID,Source,Destination) VALUES(1, '%MAILSERVER', 'any');

INSERT INTO policies (Name,Priority,Description) VALUES ('PoliticaLANInterna',1,'Primer politica con LAN');
INSERT INTO policy_members (PolicyID,Source,Destination) VALUES(2, '%MIRED,!%MAILSERVER', '%DOMINIOS');

INSERT INTO policies (Name,Priority,Description) VALUES ('PoliticaLANExterna',2,'Primer politica con LAN');
INSERT INTO policy_members (PolicyID,Source,Destination) VALUES(3, '%MIRED,!%MAILSERVER', '!%DOMINIOS');

INSERT INTO policies (Name,Priority,Description) VALUES ('Salida',3,'Politica para usuarios externos');
INSERT INTO policy_members (PolicyID,Source,Destination) VALUES(4, '!%DOMINIOS', '%DOMINIOS');

/* Asignamos una quota a cada politica, que define entre otras cosas la unidad de tiempo en la cual se define */
/* Este tiene onda, es casi exactamente uno menos de lo que se especifica en este */
INSERT INTO quotas (PolicyID,Name,Track,Period,Verdict,Data) VALUES (1, 'Min_PoliticaMailServer','Sender:user@domain', 60, 'DEFER', 'Se difieren los mensajes fuera de cuota');
/* Y ahora asignamos a la cuota, propiamente un volumen permitido */
INSERT INTO quotas_limits (QuotasID,Type,CounterLimit) VALUES(1, 'MessageCount', 125);
/* Este es otro par quota - quota_limits que pertenece a la misma política */
INSERT INTO quotas (PolicyID,Name,Track,Period,Verdict,Data) VALUES (1, 'Hor_PoliticaMailServer','Sender:user@domain', 3600, 'REJECT', 'Se rechazan los mensajes fuera de cuota');
INSERT INTO quotas_limits (QuotasID,Type,CounterLimit) VALUES(2, 'MessageCount', 480);

/* Desde Red LAN hacia cuentas de nuestros dominios */
INSERT INTO quotas (PolicyID,Name,Track,Period,Verdict,Data) VALUES (2, 'Min_PoliticaLANInterna','Sender:user@domain', 60, 'DEFER', 'Se difieren los mensajes fuera de cuota');
INSERT INTO quotas_limits (QuotasID,Type,CounterLimit) VALUES(3, 'MessageCount', 60);
INSERT INTO quotas (PolicyID,Name,Track,Period,Verdict,Data) VALUES (2, 'Hor_PoliticaLANInterna','Sender:user@domain', 3600, 'REJECT', 'Se rechazan los mensajes fuera de cuota');
INSERT INTO quotas_limits (QuotasID,Type,CounterLimit) VALUES(4, 'MessageCount', 250);

/* Desde Red LAN hacia fuera del dominio */
INSERT INTO quotas (PolicyID,Name,Track,Period,Verdict,Data) VALUES (3, 'Min_PoliticaLANExterna','Sender:user@domain', 60, 'DEFER', 'Se difieren los mensajes fuera de cuota');
INSERT INTO quotas_limits (QuotasID,Type,CounterLimit) VALUES(5, 'MessageCount', 74);
INSERT INTO quotas (PolicyID,Name,Track,Period,Verdict,Data) VALUES (3, 'Hor_PoliticaLANExterna','Sender:user@domain', 3600, 'REJECT', 'Se rechazan los mensajes fuera de cuota');
INSERT INTO quotas_limits (QuotasID,Type,CounterLimit) VALUES(6, 'MessageCount', 400);

/* Gente externa que quiere enviar a nuestro dominio */
INSERT INTO quotas (PolicyID,Name,Track,Period,Verdict,Data) VALUES (4, 'Min_Salida','Sender:user@domain', 60, 'DEFER', 'Se difieren los mensajes fuera de cuota');
INSERT INTO quotas_limits (QuotasID,Type,CounterLimit) VALUES(7, 'MessageCount', 95);
INSERT INTO quotas (PolicyID,Name,Track,Period,Verdict,Data) VALUES (4, 'Hor_Salida','Sender:user@domain', 3600, 'REJECT', 'Se rechazan los mensajes fuera de cuota');
INSERT INTO quotas_limits (QuotasID,Type,CounterLimit) VALUES(8, 'MessageCount', 460);

Creamos la base de datos en el servidor mysql de zimbra: Creamos un directorio en ~/backup (O en cualquier directorio que como usuario zimbra tengamos permiso suficiente) para trabajar con nuestros ficheros.
zimbra@mail:~ $ mkdir ~/backup/cbpolicyd
zimbra@mail:~ $ cd ~/backup/cbpolicyd

Creamos los ficheros que con los script para creación de base de datos y para insertar nuestras reglas. Por el tamaño de ambos, creo que separarlos es una idea recomendable en vista a que sean tan sencillos como sean posibles.
zimbra@mail:~/backup/cbpolicyd $ vim -p cbpolicyd.mysql.sql minsal.mysql.sql
[... En donde colocamos el contenido de los ficheros antes expuestos ...]

Ejecutamos el cliente de mysql como usuario zimbra en el servidor, que es por mucho la forma más sencilla de acceder a él.
zimbra@mail:~/backup/cbpolicyd $ mysql
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 126452
Server version: 5.5.32-log Source distribution

Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

mysql> 

Crearemos la base de datos cbpolicyd, y le asignaremos permisos sobre ella a un usuario cbpolicyd con contraseña “Password”, valores todos que pueden cambiarse como se desee pero que en este momento son bastante descriptivos.
mysql> create database cbpolicyd;
Query OK, 1 row affected (0.00 sec)
mysql> grant all privileges on cbpolicyd.* to 'cbpolicyd'@'%' identified by 'Password';
Query OK, 0 rows affected (0.00 sec)

Ejecutamos los script para creación de base de datos y para nuestras reglas personalizadas
mysql> source cbpolicyd.mysql.sql;
Query OK, 1 row affected, 1 warning (0.00 sec)
Database changed
Query OK, 0 rows affected, 1 warning (0.00 sec)
Query OK, 0 rows affected (0.24 sec)
Query OK, 0 rows affected, 1 warning (0.00 sec)
Query OK, 0 rows affected (0.31 sec)
Query OK, 0 rows affected, 1 warning (0.00 sec)
Query OK, 0 rows affected (1.70 sec)
[...]

mysql> source dominio.mysql.sql
Database changed
Query OK, 1 row affected (0.00 sec)
Query OK, 1 row affected (0.00 sec)
Query OK, 1 row affected (0.00 sec)
[...]

Por último, en un intento de normalización, movemos los script que hayamos creado a la locación por defecto para datos de cbpolicyd en ~/data/cbpolicyd/db/, donde hallaremos entre otras cosas el fichero sqlite que usaría por defecto:
mysql> quit
zimbra@mail:~ $ mv *sql ~/data/cbpolicyd/db/

Ahora podemos habilitar cbpolicyd en nuestro servidor zimbra:
zmprov ms `zmhostname` +zimbraServiceEnabled cbpolicyd

Uno o dos minutos después, zmconfigd se encargará de poner todo en marcha por primera vez. Configuramos el fichero /opt/zimbra/conf/cbpolicyd.conf.in, desde donde se crea la configuración de cbpolicyd en /opt/zimbra/conf/cbpolicyd.conf con cada reinicio de zmconfigd, de manera que el DSN por defecto quede comentarizado y hallamos agregado uno que apunte hacia nuestra base de datos en el servidor mysql:
[...]
#DSN=DBI:SQLite:dbname=@@cbpolicyd_db_file@@
DSN=DBI:mysql:database=cbpolicyd;host=127.0.0.1;port=7306
Username=cbpolicyd
Password=Password
[...]

Reiniciamos el servicio, y en cuanto esté arriba todas las reglas empezarán a surgir efecto:
zmcbpolicydctl restart

viernes, 10 de abril de 2015

Notas sobre la forma de hacer nateo respecto a rutas

Este post será dentro de poco algo obsoleto, en cuanto el nateo será una técnica inútil cuando IPv6 termine su despliegue, sin embargo, aprovecho a subir estas notas porque en ningún lugar hacen bien excepto aquí
De este esquema hablo
¿Podría este esquema acceder a un FTP en Sucursal?
Totalmente, siempre y cuando entre el Firewall y y Sucursal no se este nateando el tráfico desde LAN, ya que estamos nateando el tráfico de LAN en Firewall, lo que haría un segundo nateo (Nadie en sus cabales lo haría, pero yo no estaba en mis cabales el día que jugué con una configuración de ese tipo )

Rutas
En una configuración de primer o segundo caso completas, es necesario configurar rutas para especificar cual es el gateway que deben usar para llegar a tal ruta, y en consecuencia, que interfaz física han de buscar para salir. (Si bien se haya configurado la ip en una interfaz virtual, lo importante es la física sobre la que esa interfaz virtual trabaja)

Las interfaces virtuales son un chiste dentro de la configuración de iptables
Es bastante común que se configure la interfaz hacia DMZ (Central + Sucursal) como una interfaz virtual respecto a la interfaz hacia internet.

En ese caso, iptables toma en cuenta la interfaz fisica debido a que es lo que la configuración de rutas toma en cuenta.

Para ejemplo: Habiendo configurado como rutas adicionales
route add -net  192.168.10.0 gw 172.16.2.1
route add -net  192.168.83.0 gw 172.16.2.1
route add -net  192.168.85.0 gw 172.16.2.1
route add -net  192.168.87.0 gw 172.16.2.1
Y estando configurada 172.16.2.1 sobre una interfaz virtual eth0:1, las rutas para el sistema deberían aparecer de la siguiente forma
root@firewall:~# route -n

Kernel IP routing table
Destination     Gateway         Genmask         Flags Metric Ref    Use Iface
0.0.0.0         192.168.10.25   0.0.0.0         UG    0      0        0 eth0
10.10.20.0      172.16.2.1      255.255.255.0   UG    0      0        0 eth0
10.20.20.0      0.0.0.0         255.255.255.0   U     0      0        0 eth1
10.30.20.0      0.0.0.0         255.255.255.0   U     0      0        0 eth2
172.16.2.0      0.0.0.0         255.255.255.0   U     0      0        0 eth0
192.168.10.0    0.0.0.0         255.255.255.224 U     0      0        0 eth0
192.168.83.0    172.16.2.1      255.255.255.0   UG    0      0        0 eth0
192.168.85.0    172.16.2.1      255.255.255.0   UG    0      0        0 eth0
192.168.87.0    172.16.2.1      255.255.255.0   UG    0      0        0 eth0
Hice un experimento para demostrarme lo anterior, y no es del todo complicado una vez que se entiende lo hasta ahora expuesto, pero como yo no lo entendía casi me mata
 Imagínemos que hemos configurado firewall, y que tenemos acceso a nebula, que es un equipo que se encuentra entre Firewall y DMZ (Central + Sucursal). En la vida real, este es un proveedor de enlaces, pero el experimento va de configurar un equipo cualquiera como nebula con apenas forwarding de paquetes y un par de reglas en la cadena POSTROUTING en la tabla nat de iptables

Cuando Firewall muestra esto:
root@firewall:~# iptables -t nat -nvL POSTROUTING
Chain POSTROUTING (policy ACCEPT 0 packets, 0 bytes)
 pkts bytes target     prot opt in     out     source               destination        
    3   189 ACCEPT     all  --  *      eth0    10.20.20.0/24        10.10.20.0/24        /* Vamos hacia DMZ */
    3   180 MASQUERADE  all  --  *      eth0    10.20.20.0/24        0.0.0.0/0            match-set rwa dst /* Vamos hacia RWA */
    0     0 MASQUERADE  all  --  *      eth0    10.20.20.0/24        0.0.0.0/0            /* Vamos hacia Internet */
Nebula nebula dice estar nateando de esta manera:
root@nebula:~# iptables -t nat -nvL POSTROUTING
Chain POSTROUTING (policy ACCEPT 5 packets, 1058 bytes)
 pkts bytes target     prot opt in     out     source               destination        
    3   189 MASQUERADE  all  --  *      br0     10.20.20.0/24        0.0.0.0/0          
    3   180 MASQUERADE  all  --  *      br0     172.16.2.0/24        0.0.0.0/0  
Cuando el destino desde la red $LAN era 10.10.20.0, #firewall no lo natea en realidad, por tanto llega a #nebula con su ip original como se puede ver, y hace coincidencia en la regla esperada para tal fin, en el ejemplo la primera
Luego, cuando el destino eran los grupos en rwa, (que de hecho incluyen a 10.10.20.0/24, pero al anteponer la regla anterior en el orden de iptables nunca llegará a este punto) #firewall nateo con salida en la interfaz eth0, pero hay que fijarse en eth0
root@firewall:~# ip addr show eth0
2: eth0:  mtu 1500 qdisc pfifo_fast state UP qlen 1000
    link/ether 52:54:00:de:78:a8 brd ff:ff:ff:ff:ff:ff
    inet 172.16.2.15/24 brd 172.16.2.255 scope global eth0:1
    inet 192.168.10.15/27 brd 192.168.10.31 scope global eth0
    inet6 fe80::5054:ff:fede:78a8/64 scope link
       valid_lft forever preferred_lft forever 
Si bien se especifica la interfaz eth0 en su totalidad, iptables en #firewall natea la salida con la ip 172.16.2.15/24, (Puede observarse que pertenece a eth0:1 porque fue creada con ifconfig). La prueba de dicho nateo esta en que en #nebula se ha hecho coincidencia en la regla para nateo de 172.16.2.0/24, no de 192.168.10.0/27 (Regla que de hecho no existe en #nebula), porque en la tabla de ruteo mostrada arriba se especifica que hacia las redes en el grupo ipset #rwa es a traves de  172.16.2.1

Es obvio que llegando a este punto mi explicación podría ser insuficiente para entender, confió en que las tablas que he colocado sean de hecho más explicativas por si mismas

Para arrancar un nebula como el que use para revisar todo la teoría

Nebula debe conocer esas redes que natea, para que cuando le devuelvan las peticiones el sepa a donde putas debe enviarlas:
root@nebula:~# route -n
Kernel IP routing table
Destination     Gateway         Genmask         Flags Metric Ref    Use Iface
0.0.0.0         192.168.10.1    0.0.0.0         UG    0      0        0 br0
10.20.20.0      172.16.2.15     255.255.255.0   UG    0      0        0 br1
10.30.20.0      0.0.0.0         255.255.255.0   U     0      0        0 virbr2
172.16.2.0      0.0.0.0         255.255.255.224 U     0      0        0 br1
172.16.3.0      0.0.0.0         255.255.255.0   U     0      0        0 br1
192.168.10.0    0.0.0.0         255.255.255.224 U     0      0        0 br0
Nateamos
iptables -t nat -D POSTROUTING -o br0 -s 192.168.10.0/24 -j MASQUERADE
iptables -t nat -A POSTROUTING -o br0 -s 172.16.2.0/24 -j MASQUERADE
iptables -t nat -A POSTROUTING -o br0 -s 172.16.3.0/24 -j MASQUERADE

Otros apuntes interesantes

Otros apuntes interesantes