Postfix - amavisd-new sin localhost o servidor de correo de una nueva manera

Hay muchas instrucciones sobre cómo elevar el servidor de correo en un montón de postfix - amavisd-new - dovecot. Y la gran mayoría de ellos se repiten casi al pie de la letra, incluidos errores e inexactitudes.

Me parece aburrido presionar los botones sin pensarlo, así que decidí optimizar la configuración estándar: ¿qué pasa si construyo la interacción de postfix y amavisd-new no a través de localhost, sino en un socket unix?

Al final resultó que, no todo es tan simple, ¡pero lo hice! Instrucción y parche debajo del corte.

Honestamente, generalmente no me gusta la interacción a través de localhost dentro de la misma máquina. Si desea organizar el intercambio de datos entre dos aplicaciones, entonces es mucho más correcto, más seguro y requiere menos recursos hacer esto a través de un socket Unix en el sistema de archivos. Además, de esta manera puede organizar la protección (por medio de derechos en el sistema de archivos) incluso cuando está ausente a nivel de aplicación o protocolo.

Entonces, la ruta de correo en el grupo discutido se ve así:



Resulta que necesitamos organizar dos conexiones: cuando se transfiere al filtrado y cuando se regresa al MTA. Dado que el socket es creado por el oyente, en el primer caso será amavisado, y en el segundo, postfix.

Comencemos con el segundo, porque es más simple y está mejor descrito. Para que postfix cree un socket de escucha, solo necesita especificar unix, no inet, en la segunda columna de master.cf (columna de tipo). En este caso, la primera columna define la ruta y el nombre del archivo del socket.

Dado que los procesos de postfix funcionan en chroot (esto puede deshabilitarse para un proceso específico, pero no vale la pena), debe crear una carpeta dentro del directorio de inicio de postfix: / var / spool / postfix. Tendrá ambos enchufes:

mkdir /var/spool/postfix/amavis chown amavis:postfix /var/spool/postfix/amavis chmod 770 /var/spool/postfix/amavis 

Configuración de pozo y postfix:

 amavis/postfix-in unix y - y - - smtpd -o smtpd_client_restrictions=$local_clients_only -o smtpd_helo_restrictions= -o smtpd_sender_restrictions= -o smtpd_recipient_restrictions= -o smtpd_milters= 

Las opciones específicas dependen de su configuración, esta es mi opción.

Hay dos problemas:

  1. La ruta será relativa a / var / spool / postfix / private, que está sujeta a permisos muy estrictos.
  2. No estoy seguro de si esto es cierto en todas las distribuciones, pero en Ubuntu con seguridad. Es mejor no tocar los derechos de la carpeta (los sockets de todos los servicios de postfix están ahí), es mejor crear un enlace simbólico.
  3. Además del socket, postfix también crea un archivo pid para el proceso, cuyo nombre es generado automáticamente por la máscara de $ type. $ Name. Donde type será igual a unix, y el nombre se toma de la primera columna de master.cf. Resulta unux.amavis / postfix-in, es decir archivo en una subcarpeta. Él mismo no lo creará y caerá con un error.

Entonces, sustituimos las muletas:

 cd /var/spool/postfix/private ln -s ../amavis . mkdir /var/spool/postfix/pid/unix.amavis 

No es muy agradable, pero no es destructivo para la estructura de carpetas normal del paquete.

Reiniciamos postfix y nos aseguramos de que el archivo socket aparezca en la carpeta amavis y el archivo pid en pid / unix.amavis. Desafortunadamente, los derechos del socket son 666, pero los derechos de la carpeta que creó anteriormente protegerán el archivo de ojos innecesarios.

Puede verificar el trabajo con el comando:

 netcat -U /var/spool/postfix/amavis/postfix-in 220 mail.example.ru ESMTP Postfix 

Pues lo hicieron. Ahora para amavisd.

Primero, configure la ruta de retorno del correo a través del socket Unix propiedad de Postfix. Esto funciona fuera de la caja:

 $forward_method = 'smtp:/var/spool/postfix/amavis/postfix-in'; $notify_method = \$forward_method; 

Bueno, ahora la parte más difícil es configurar enchufes en amavisd. La solución se puede encontrar en Internet , pero allí se propone utilizar un solo socket especificado por el parámetro $ unix_socketname. También quería mi propio protocolo amavisd-new (AM.PDP) y recepción de correo a través de sockets.

El archivo de configuración predeterminado contiene una referencia a la directiva @listen_sockets, pero no tiene una descripción. ¡Pero está en las notas de la versión , incluso con ejemplos! Es cierto, solo hay un zócalo, pero ¿qué le impide intentarlo?

OK, pero ¿cómo configurar el protocolo para el socket (que se especifica en el banco de políticas)? En todos los ejemplos, simplemente escriben SOCK. Por analogía con los zócalos de entrada (puede especificar el puerto host allí), le sugerí que necesitara especificar la ruta completa al archivo del zócalo. Esto es lo que sucedió:

 $unix_socketname = undef; $inet_socket_bind = undef; $inet_socket_port = undef; @listen_sockets = ('/var/lib/amavis/amavisd.sock', '/var/spool/postfix/amavis/amavis-in.sock'); $unix_socket_mode = 0660; %interface_policy = ( '/var/lib/amavis/amavisd.sock' => 'AM.PDP-SOCK', '/var/spool/postfix/amavis/amavis-in.sock' => 'LMTP-SOCK' ); $policy_bank{'LMTP-SOCK'} = { protocol => 'LMTP' }; $policy_bank{'AM.PDP-SOCK'} = { protocol => 'AM.PDP', auth_required_release => 0, # don't require secret-id for release }; 

Reiniciar, verificar, de hecho, ¡se han creado ambos enchufes! Victoria En realidad, no, cuando intentas conectarte al socket, no sucede nada y se escribe un error en el registro que indica que el protocolo no está definido para él. Resulta que el banco de pólizas no se aplica a ellos.

¿Cómo es eso? Tuve que ir al código.

Esta campaña trajo dos novedades: como siempre, buenas y malas. Lo bueno es que la suposición con respecto a% interface_policy era correcta:

 # load policy banks according to my socket (destination), # then check for allowed access from the peer (client/source) # sub access_is_allowed($;$$$$) { my($unix_socket_path, $src_addr, $src_port, $dst_addr, $dst_port) = @_; my(@bank_names); if (defined $unix_socket_path) { push(@bank_names, $interface_policy{"SOCK"}); push(@bank_names, $interface_policy{$unix_socket_path}); } elsif (defined $dst_addr && defined $dst_port) { $dst_addr = '['.lc($dst_addr).']' if $dst_addr =~ /:[0-9a-f]*:/i; # IPv6? push(@bank_names, $interface_policy{$dst_port}); push(@bank_names, $interface_policy{"$dst_addr:$dst_port"}); } load_policy_bank($_) for @bank_names; 

Lo malo es que $ unix_socket_path entra en esta función vacía. Se llena de la siguiente manera:

 my $is_ux = $sock && $sock->UNIVERSAL::can('NS_proto') && $sock->NS_proto eq 'UNIX'; 

Y ambas propiedades están vacías allí.

Un estudio de la documentación sugirió esta opción:

 my $unix_socket_path = $sock->hostpath(); 

¡Y funcionó! Listo .patch se puede decir aquí .

Ahí está el toque final. Dado que amavisd crea su propio socket con derechos solo para sí mismo, y hemos denegado el acceso al resto (lo cual es cierto), necesitamos agregar postfix al grupo amavis para que pueda escribir en el socket:

 gpasswd -a postfix amavis 

Listo

PD: envié el parche y la descripción del problema por Mark Martinec por correo ya que no encontré ninguna mención del rastreador de errores en el sitio . Todavía no he recibido una respuesta, pero realmente no cuento con eso: el proyecto parece abandonado (el último lanzamiento hace más de dos años).

Source: https://habr.com/ru/post/es415597/


All Articles