使用Postfix,Dovecot,MySQL搭建的邮件服务器

前阵子和几位朋友一同建起了一个小社区网站,期间搭建了一个团队服务器用同步代码和收发邮件,搭建邮件服务还是头一回。现在现成的邮件服务器解决方案也是有的,不过还是自己搭建了一遍,熟悉了一下具体流程。这两天在自己的服务器上也部署了,大致记录下:

结构:

Postfix 提供 SMTP,submission 服务,并对请求进行过滤,转发。SMTP 是邮件投递的基础。Postfix 各种功能可以添加外部实现,比如这里会将 Virtual Mail 通过 LMTP 转给Dovecot,Email 信息查询部分由 MySQL 提供,通过 pypolicyd-spf 进行过滤,用户验证也由 Dovecot 完成。

Dovecot 负责 IMAP 等服务的请求和用户验证,管理虚拟用户的邮箱内容等,和Postfix通过 LMTP 链接。

使用 MySQL 存储邮箱用户的账户信息,MySQL是可选的存储方式之一。

为了安全起见所有链接均用了加密的方式,普通 STMP,IMAP 链接强制必须使用 STARTTLS 升级为安全链接,STMPS,IMAPS 链接和 HTTPS 一样一开始就为加密链接。

安装Postfix、Dovecot、MySQL、pypolicyd-spf

视不同发行版安装相应的包即可。

 

配置:

系统:

建立vmail用户,vmail文件夹

useradd -s /sbin/nologin -d /var/vmail -m -r -g mail vmail

chown vmail:mail /var/vmail

chmod o-rwx vmail /var/vmail

grep vmail /etc/passwd | awk -F : '{print $3}'

建立并获得的vmail的uid,稍后会用到。

也可以指定uid建立vmail用户:

useradd -s /sbin/nologin -d /var/vmail -m -r -u <uid> vmail

建立 aliases.db(如果不存在的话),Postfix会用到

touch /etc/alises

newaliases

MySQL:

初次开启的话记得运行一下mysql_secure_installation。

通过 mysql -u root -p 输入密码进入 Mysql,参考以下步骤建表,插入数据。

create user vmail@localhost identified by 'vmailpassword';

create database vmail;

grant select on vmail.* to vmail@localhost identified by 'vmailpassword';

use vmail;

create table domains (name char(30) not null primary key);

create table users (email char(64) not null primary key, password char(128) not null, domain char(30) not null, foreign key (domain) references domains(name));

create table aliases (source char(64) not null primary key, destination char(64) not null, foreign key (destination) references users(email));

insert into domains values('----.com');

insert into users values('[email protected]', ENCRYPT('--password--here--', CONCAT('$6$', SUBSTRING(SHA(RAND()), -16))),'----.com');

insert into aliases values ('[email protected]', '[email protected]');

domains表存放virtual domian,user表存放可登陆的用户邮箱和密码。

Postfix 配置:

配置文件:

注意修改前备份,方便恢复和参考。主要修改以下参数:

设置服务器信息,有单个服务器的情况下设置比较简单,domain为服务器域名:

mydestination 不可与 virtual main domain 冲突,否则发往 Dovecot 的邮件会被 Postfix 截下来,一般会找不到用户而 Reject,如果正好有重名的用户的话应该会发往错误的用户。

mydestination = localhost
mydomain = <domain>
myorigin = <domain>
myhostname = <domain>
mynetworks = 127.0.0.0/8
mynetworks_style = host
relay_domains =

TLS证书设置:

smtpd_tls_cert_file = /etc/ssl/private/----crt----
smtpd_tls_key_file = /etc/ssl/private/----key----
smtpd_tls_CApath = /etc/ssl/certs
smtpd_use_tls = yes

SASL支持设置,设置为不兼容老旧客户端:

smtpd_sasl_type = dovecot
smtpd_sasl_path = private/auth
smtpd_sasl_auth_enable = yes
smtpd_sasl_security_options = noanonymous, noactive, nodictionary
smtpd_sasl_local_domain = $mydomain
broken_sasl_auth_clients = no

一些安全强化选项,使用高强度的加密算法,和启用TLS,以及设置空的readme文件夹等。

smtpd_tls_mandatory_exclude_ciphers = aNULL, eNULL, EXPORT, DES, RC4, MD5, PSK, aECDH, EDH-DSS-DES-CBC3-SHA, EDH-RSA-DES-CDC3-SHA, KRB5-DE5, CBC3-SHA
smtpd_tls_mandatory_ciphers = high
smtpd_tls_mandatory_protocols = !SSLv2, !SSLv3, TLSv1, TLSv1.1, TLSv1.2
smtpd_tls_exclude_ciphers = $smtpd_tls_mandatory_exclude_ciphers
smtpd_tls_ciphers = $smtpd_tls_mandatory_ciphers
smtpd_tls_protocols = $smtpd_tls_mandatory_protocols
smtpd_tls_auth_only = yes
smtpd_tls_dh1024_param_file = /etc/postfix/dh2048.pem
smtpd_tls_dh512_param_file = /etc/postfix/dh512.pem
smtpd_tls_eecdh_grade = ultra
smtpd_tls_security_level = may
smtpd_tls_loglevel = 1
smtpd_tls_received_header = yes

# outgoing
smtp_tls_mandatory_exclude_ciphers = aNULL, eNULL, EXPORT, DES, RC4, MD5, PSK, aECDH, EDH-DSS-DES-CBC3-SHA, EDH-RSA-DES-CDC3-SHA, KRB5-DE5, CBC3-SHA
smtp_tls_mandatory_ciphers = high
smtp_tls_mandatory_protocols = !SSLv2, !SSLv3, TLSv1, TLSv1.1, TLSv1.2
smtp_tls_exclude_ciphers = $smtp_tls_mandatory_exclude_ciphers
smtp_tls_ciphers = $smtp_tls_mandatory_ciphers
smtp_tls_protocols = $smtp_tls_mandatory_protocols
smtp_tls_security_level = may
smtp_tls_note_starttls_offer = yes
smtp_tls_loglevel = 1


tls_random_source = dev:/dev/urandom
tls_preempt_cipherlist = yes
# Log the hostname of a remote SMTP server that offers STARTTLS, when TLS is not already enabled for that server. 

# No readme for more security
readme_directory = no
sample_directory = no

生成对应的文件,在Shell中执行以下语句:

openssl dhparam -out /etc/postfix/dh2048.pem 2048
openssl dhparam -out /etc/postfix/dh512.pem 512

如果强制启用TLS的话,将上面的 *_level = may 改为 enforce。不过会导致和一些邮箱不兼容,比如126,163。

一些行为配置,酌情修改:

在找不到收信人的情况下返回永久错误,让发信服务器不再重试投递:

unknown_local_recipient_reject_code = 550

超时和错误次数限制:

# Time before log a delayed warning
delay_warning_time = 4h
# how long to keep message on queue before return as failed.
maximal_queue_lifetime = 7d
# max and min time in seconds between retries if connection failed
minimal_backoff_time = 1000s
maximal_backoff_time = 8000s
# how long to wait when servers connect before receiving rest of data
smtp_helo_timeout = 60s
# how many address can be used in one message.
# effective stopper to mass spammers, accidental copy in whole address list
# but may restrict intentional mail shots.
smtpd_recipient_limit = 16
# how many error before back off.
smtpd_soft_error_limit = 3
# how many max errors before blocking it.
smtpd_hard_error_limit = 12

配置和Dovecot的链接参数:

通过lmtp协议连接到dovecot,设置vmail的文件夹,用户等参数。

其中 uid 为 vmail 的 uid,gid 为 mail 的 gid,如果不是12的话酌情修改。(grep mail /etc/group)

virtual_transport = lmtp:unix:private/dovecot-lmtp
address_verify_virtual_transport = lmtp:unix:private/dovecot-lmtp
virtual_mailbox_domains = mysql:/etc/postfix/mysql-virtual-mailbox-domains.cf
virtual_mailbox_maps = mysql:/etc/postfix/mysql-virtual-mailbox-maps.cf
virtual_alias_maps = mysql:/etc/postfix/mysql-virtual-alias-maps.cf
virtual_mailbox_base = /var/vmail
virtual_uid_maps = static:998
virtual_gid_maps = static:12

其中一些位置可以写死,减少SQL调用,比如只有一个 virtual_mailbox_domain:

virtual_mailbox_domains = ----.com

其中需要三个SQL查询用的配置文件:

/etc/postfix/mysql-virtual-mailbox-domains.cf:

vim mysql-virtual-mailbox-domains.cf

user = vmail
password = vmailpassword
hosts = 127.0.0.1
dbname = vmail
query = SELECT 1 FROM domains WHERE name='%s'

mysql-virtual-mailbox-maps.cf:

vim /etc/postfix/mysql-virtual-mailbox-maps.cf

user = vmail
password = vmailpassword
hosts = 127.0.0.1
dbname = vmail
query = SELECT 1 FROM users WHERE email='%s'

/etc/postfix/mysql-virtual-alias-maps.cf:

vim /etc/postfix/mysql-virtual-alias-maps.cf

user = vmail
password = vmailpassword
hosts = 127.0.0.1
dbname = vmail
query = SELECT destination FROM aliases WHERE source='%s'

最后邮件发送/接受限制,阻止一些简单的垃圾/骚扰邮件:

强制 Client 发送 HELO,启用 REJECT DELAY 和下面的 client 中的 reject_unknown_client_hostname 过滤配合,只让有MX记录/通过验证的用户使用SMTP,禁用VRFY:

smtpd_helo_required = yes
smtpd_delay_reject = yes
disable_vrfy_command = yes

restriction 规则:

tpd_client_restrictions = reject_unauth_pipelining, permit_mynetworks, permit_sasl_authenticated, warn_if_reject, reject_plaintext_session, reject_unknown_client_hostname, permit
smtpd_relay_restrictions = reject_unauth_pipelining, permit_mynetworks, permit_sasl_authenticated, warn_if_reject, reject_non_fqdn_recipient, reject_unknown_recipient_domain, reject_unauth_destination, check_policy_service unix:private/policyd-spf, permit
smtpd_helo_restrictions = reject_unauth_pipelining, permit_mynetworks, permit_sasl_authenticated, warn_if_reject, reject_invalid_helo_hostname, reject_non_fqdn_helo_hostname, reject_unknown_helo_hostname, permit
smtpd_sender_restrictions = reject_unauth_pipelining, permit_mynetworks, permit_sasl_authenticated, warn_if_reject, reject_non_fqdn_sender, reject_unknown_sender_domain, reject_unverified_sender, permit
smtpd_recipient_restrictions = reject_unauth_pipelining, permit_mynetworks, permit_sasl_authenticated, warn_if_reject, reject_non_fqdn_recipient, reject_unknown_recipient_domain, reject_unauth_destination, check_policy_service unix:private/policyd-spf, permit
smtpd_data_restrictions = reject_unauth_pipelining, permit_mynetworks, permit_sasl_authenticated, warn_if_reject, reject_multi_recipient_bounce, permit
smtpd_end_of_data_restrictions = reject_unauth_pipelining, permit_mynetworks, permit_sasl_authenticated, warn_if_reject, reject_multi_recipient_bounce, permit
smtpd_etrn_restrictions = reject

SPF设置:延长SPF验证超时时间:

policy_time_limit = 3600

 

编辑 /etc/postfix/master.cf 加入以下来开启SPF服务,配合上面的过滤:

policyd-spf  unix  -       n       n       -       0       spawn
  user=tpe argv=/usr/bin/policyd-spf /etc/policyd-spf/policyd-spf.conf

继续编辑 /etc/postfix/master.cf ,开启SMTP服务:

smtp      inet  n       -       n       -       -       smtpd
...

submission inet n       -       n       -       -       smtpd
-o syslog_name=postfix/submission
-o smtpd_tls_security_level=encrypt
-o smtpd_sasl_auth_enable=yes
....

smtps     inet  n       -       n       -       -       smtpd
-o syslog_name=postfix/smtps
-o smtpd_tls_wrappermode=yes
-o smtpd_sasl_auth_enable=yes
....

smpts工作于wraper模式,即不要STARTTLS,直接建立TLS链接,其他参数按照main.cf为默认不修改。

执行:

postfix set-permissions

service postfix start

启动 postfix。

 

Dovecot:

配置文件,修改前注意备份:

编辑 /etc/dovecot/dovecot.conf,开启 imap lmtp。 imap 提供外部访问,lmtp给postfix用。

protocols = imap lmtp

需要这一行来加载conf.d中的配置文件。

!include conf.d/*.conf

 

编辑 /etc/dovecot/conf.d/10-mail.conf,指定vmail的文件位置和UID,GID,同时限制Dovecot能使用的GID,UID。如果inbox没有启用的话,取消注释启用。

mail_location = maildir:/var/vmail/%d/%n

mail_uid = vmail
mail_gid = mail

first_valid_uid = 998
last_valid_uid = 998

first_valid_gid = 12
last_valid_gid = 12

 

编辑: /etc/dovecot/conf.d/10-auth.conf,设置验证:

disable_plaintext_auth = yes

auth_mechanisms = plain login

注释除了sql以外的验证途径,仅保留:

!include auth-sql.conf.ext

编辑 conf.d/auth-sql.conf.ext,配置SQL验证的参数:

密码通过MySQL验证,用户登陆后使用的GID,UID统一使用vmail,mail,文件位置统一为/var/mail/。

passdb {
driver = sql

# Path for SQL configuration file, see example-config/dovecot-sql.conf.ext
args = /etc/dovecot/dovecot-sql.conf.ext
}

userdb {
driver = static
args = uid=vmail gid=vmail home=/var/vmail/%d/%n
}

编辑 /etc/dovecot/dovecot-sql.conf.ext,配置查询语句:

driver = mysql

connect = host=localhost dbname=vmail user=vmail password=vmailpassword

default_pass_scheme = SHA512-CRYPT

password_query = \
SELECT email as user, password FROM users WHERE email='%u';

 

编辑 /etc/dovecot/conf.d/10-logging.conf,显示更多日志:

auth_verbose = yes

 

编辑 /etc/dovecot/conf.d/10-master.conf,配置 Dovecot 提供的各种服务参数:

LMTP 和 Auth 服务均以 unix socket 形式与 Postfix 链接。worker 进程以 dovecot 身份运行。socket的位置均放在 /var/spool/postfix/private/ 中:

default_internal_user = dovecot

service lmtp {
unix_listener /var/spool/postfix/private/dovecot-lmtp {
mode = 0666
}

# Create inet listener only if you can't use the above UNIX socket
#inet_listener lmtp {
# Avoid making LMTP visible for the entire internet
#address =
#port =
#}
}

service auth {
# auth_socket_path points to this userdb socket by default. It's typically
# used by dovecot-lda, doveadm, possibly imap process, etc. Users that have
# full permissions to this socket are able to get a list of all usernames and
# get the results of everyone's userdb lookups.
#
# The default 0666 mode allows anyone to connect to the socket, but the
# userdb lookups will succeed only if the userdb returns an "uid" field that
# matches the caller process's UID. Also if caller's uid or gid matches the
# socket's uid or gid the lookup succeeds. Anything else causes a failure.
#
# To give the caller full permissions to lookup all users, set the mode to
# something else than 0666 and Dovecot lets the kernel enforce the
# permissions (e.g. 0777 allows everyone full permissions).
unix_listener auth-userdb {
mode = 0666
#user =
#group =
}

# Postfix smtp-auth
unix_listener /var/spool/postfix/private/auth {
mode = 0666
}

# Auth process is run as this user.
user = $default_internal_user
}

default_internal_user = dovecot

service auth-worker {
# Auth worker process is run as root by default, so that it can access
# /etc/shadow. If this isn't necessary, the user should be changed to
# $default_internal_user.
user = $default_internal_user
}

 

编辑 /etc/dovecot/conf.d/10-ssl.conf,管理IMAP服务的链接安全性:

ssl = required

ssl_cert = </etc/ssl/private/<cert_file>
ssl_key = </etc/ssl/private/<key_file>

ssl_dh_parameters_length = 2048

ssl_protocols = !SSLv2 !SSLv3 TLSv1 TLSv1.1 TLSv1.2

ssl_cipher_list = DEFAULT:!EXPORT:!LOW:!MEDIUM:!MD5

ssl_prefer_server_ciphers = yes

其中将dh key长度设置为了2048,启动dovecot 后 dovecot 会去生成新的 ssl-parameters,如果设备性能不高的话会花费很长时间。如果ssl-parameters出现问题可以删除旧的 ssl-parameters (/var/lib/ssl-parameters.dat) 之后重启dovecot。

 

编辑 15-lda.conf,配置LMTP参数:

postmaster_address = [email protected]

hostname = --domain.com--

 

防火墙:

使用Iptables的话,需要打开以下端口:

参考设置(没启用POP3):

#imap/imaps
-A INPUT -p tcp -m tcp --dport 143 -m conntrack --ctstate NEW -j ACCEPT
-A INPUT -p tcp -m tcp --dport 993 -m conntrack --ctstate NEW -j ACCEPT
#smtp/smpts
-A INPUT -p tcp -m tcp --dport 25 -m conntrack --ctstate NEW -j ACCEPT
-A INPUT -p tcp -m tcp --dport 465 -m conntrack --ctstate NEW -j ACCEPT

重新加载iptables,postfix,dovecot,之后服务器应该就可以用了。

 

配置域名:

首先要有个域名,添加MX记录,SPF记录,MX记录用于在接收邮件的时候解析,这样其他邮件服务器可以知道给你投递邮件的话投递到什么地方,SPF记录用来判断一个IP是否有权利以此域名的名义发送邮件,防止别人冒充你。

MX记录为服务器IP即可。

TXT记录可以参考:

v=spf1 mx ~all

意为允许MX记录中的IP地址使用你的域名发信,其他地址均不能以你的名义发信。

 

完成:

邮件服务器建好了,启动服务,之后可以用Thunderbird之类的客户端登陆。

 

TODO:

反垃圾,Docker,性能,Header checker

 

在 Raspberry Pi 2 上安装 Hardened Gentoo

一段时间以前入了树梅派,想当作日后的主力服务器使用,尝试配置一个好用的服务器,而且最近比较热衷于 hardened 系统,可以提供额外的安全。

配置参考:https://wiki.gentoo.org/wiki/Raspberry_Pi

首先应该配置sd卡分区,我之前用的raspbian,打算直接用旧的分区,不动boot分区,只对root分区(mount在/mnt/ext4上)进行修改。

首先下来最新的stage3,校验,解压:

wget http://distfiles.gentoo.org/experimental/arm/hardened/stage3-armv7a_hardfp-hardened-201xxxxx.tar.bz2

wget http://distfiles.gentoo.org/experimental/arm/hardened/stage3-armv7a_hardfp-hardened-201xxxxx.DIGESTS

和 DIGESTS 对比核对下各种校验值对不对,之后解压到sd卡根目录(/mnt/ext4):

tar xvf stage3-armv7a_hardfp-hardened-201xxxxx.tar.bz2 -C /mnt/ext4/

由于正在PC上使用gentoo,直接使用cp /usr/portage ./usr/ 复制portage tree。注意先清理一下distfiles。

cp /usr/portage /mnt/ext4/usr/portage -r

如果没有现成的Portage Tree下载解压一个即可。

 

Linux Kernel and Grsecurity Patch:

配置Toolchain:

Gentoo 中可以很方便地使用 crossdev 配置:

crossdev -S -v -t armv7a-hardfloat-linux-gnueabi

或者其他方式准备工具链,之后设置环境变量:

export ARCH=arm

export CROSS_COMPILE=armv7a-hardfloat-linux-gnueabi-

export INSTALL_MOD_PATH=/mnt/ext4

export INSTALL_HDR_PATH=/mnt/ext4

export KERNEL=kernel7

准备内核代码:

git clone git://github.com/raspberrypi/linux.git

如果已有现成的Linux git repo ,而且不介意加入更多remote的话,可以通过

git remote add rasp git://github.com/raspberrypi/linux.git

git fetch rasp

更快地获得代码。

应用Grsecurity补丁,使用branch rpi-4.3.y的代码。

git checkout rasp/rpi-4.3.y

wget https://grsecurity.net/test/grsecurity-3.1-4.3.3-201xxxxxxxxx.patch

patch -p1 -s < grsecurity-3.1-4.3.3-201xxxxxxxxx.patch

有Reject,一般比较好解决,手动解决即可。

写了个小Patch,修复驱动的小问题:

diff --git a/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_shim.c b/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_shim.c
index 8072ff6..74c3af3 100644
--- a/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_shim.c
+++ b/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_shim.c
@@ -39,8 +39,6 @@

#include "vchiq_util.h"

-#include <stddef.h>
-
#define vchiq_status_to_vchi(status) ((int32_t)status)

typedef struct {
diff --git a/drivers/net/wireless/rtl8192cu/include/hal_intf.h b/drivers/net/wireless/rtl8192cu/include/hal_intf.h
index cac4408..2c08180 100644
--- a/drivers/net/wireless/rtl8192cu/include/hal_intf.h
+++ b/drivers/net/wireless/rtl8192cu/include/hal_intf.h
@@ -231,7 +231,7 @@ struct hal_ops {

s32 (*c2h_handler)(_adapter *padapter, struct c2h_evt_hdr *c2h_evt);
c2h_id_filter c2h_id_filter_ccx;
-};
+} __no_const;

typedef        enum _RT_EEPROM_TYPE{
EEPROM_93C46,
diff --git a/drivers/net/wireless/rtl8192cu/include/rtw_io.h b/drivers/net/wireless/rtl8192cu/include/rtw_io.h
index daf342ac..1ef9295 100644
--- a/drivers/net/wireless/rtl8192cu/include/rtw_io.h
+++ b/drivers/net/wireless/rtl8192cu/include/rtw_io.h
@@ -152,7 +152,7 @@ struct _io_ops
void (*_read_port_cancel)(struct intf_hdl *pintfhdl);
void (*_write_port_cancel)(struct intf_hdl *pintfhdl);

-};
+} __no_const;

准备config,通过menuconfig开关一下Grsecurity的安全选项:

make bcm2709_defconfig

make menuconfig

按需修改,测试发现需要关闭以下Grsecurity相关标记,不然树梅派会不能启动。CONFIG_PAX_KERNEXEC,CONFIG_PAX_MEMORY_UDEREF,CONFIG_GRKERNSEC_RANDSTRUCT

注意:使用CONFIG_DEBUG_RODATA 会让 Grsecurity 的 RBAC 无法开启,开启会导致Kernel Panic。

编译内核,模块,Devtree。

make zImage modules dtbs

安装新内核:

make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- INSTALL_MOD_PATH=mnt/ext4 modules_install

make headers_install

cp mnt/fat32/$KERNEL.img mnt/fat32/$KERNEL-backup.img

scripts/mkknlimg arch/arm/boot/zImage mnt/fat32/$KERNEL.img

cp arch/arm/boot/dts/*.dtb mnt/fat32/

cp arch/arm/boot/dts/overlays/*.dtb* mnt/fat32/overlays/

cp arch/arm/boot/dts/overlays/README mnt/fat32/overlays/

sync

sudo umount mnt/fat32

sudo umount mnt/ext4

修改fstab,加上boot挂载点。

塞入SD可以开机了,其余参考Wiki配置即可。

 

相关连接:

树梅派官方内核编译向导:

https://www.raspberrypi.org/documentation/linux/kernel/building.md

Gentoo Wiki相关:

https://wiki.gentoo.org/wiki/Raspberry_Pi/Quick_Install_Guide

https://wiki.gentoo.org/wiki/Raspberry_Pi/Cross_building

已经打好补丁的Patch:

https://github.com/ryncsn/linux

由于GRSEC违反GPL2协议,应该不会再有更新了,默哀。

搭建自配置可用的IPv6网络

为了能有IPv6链接,在重新配置了系统之后又把以前做过的 Radvd 和 使用 HE 提供的 Tunnel Broker 的服务又配置了一遍:

首先要有一个 Hurrican Electric 的 Tunnel Broker 帐号,注册很方便,过程略。

内核要开启Tunnel支持,可见链接中的Wiki。

自用的配置脚本:

由于我用的ADSL拨号网络IP总是变化,所以不能用固定的文件去配置,需要一枚脚本:

https://github.com/ryncsn/he-ipv6-init-script/raw/master/hev6.sh

放到/usr/local/sbin/

wget https://raw.githubusercontent.com/ryncsn/he-ipv6-init-script/master/hev6.sh -O /usr/local/sbin/hev6-init

vim /usr/local/sbin/hev6-init

按照 Tunnel Broker 帐号和申请的 Tunnel 信息配置开头的各种变量,INTERFACE是 Tunnel 经过的的 Interface,需要能接受服务器发来的 6in4 (Protocal 41) 包,且有独立公网地址。ROUTE_INTERFACE是本地需要提供IPv6网络的接口,对我来说就是内网。

 

配置服务:

要让服务自启动。之后写一个服务资源文件:

Gentoo中:

vim /etc/init.d/hev6-init
#!/sbin/runscript
# Copyright 1999-2013 Gentoo Foundation
# Distributed under the terms of the GNU General Public License v2
# $Id$

description="Hurrican Electric Tunnel Broker"

command="/usr/local/sbin/hev6-init"

log_file="/var/log/hev6"
depend() {
        need net
        use logger dns
}

start() {
        ebegin "Starting DDNS on ${IFACE}"
        start-stop-daemon --start --background \
        --stdout $log_file --stderr $log_file \
        --exec $command
}

stop() {
        ebegin "Stopping HE v6 tunnel"
        $command clear
        eend $?
}

启用,启动服务。

rc-update add hev6-init default

service hev6-init start

Systemd版:

vim /etc/systemd/system/hev6.service
[Unit]
Description=Hurrican Electric IPv6 Tunnel Broker
After=syslog.target network.target remote-fs.target nss-lookup.target

[Service]
TimeoutSec=0
PIDFile=/run/hev6.pid
ExecStart=/usr/local/sbin/hev6-init
ExecStop=/usr/local/sbin/hev6-init clear
Restart=on-failure


[Install]
WantedBy=multi-user.target
systemctl enable hev6

systemctl start hev6

服务启动之后通过ping6 ipv6.google.com测试,无问题。

 

配置Radvd:

配置radvd,在要提供IPv6服务的接口上开启路由通知:

emerge radvd

vim /etc/radvd.conf

参考配置,酌情修改网段信息等:

interface eth0
{       
        AdvSendAdvert on;
        
        MinRtrAdvInterval 3;
        MaxRtrAdvInterval 10;
        
        AdvDefaultPreference low;               
        AdvHomeAgentFlag off;
        
        prefix 2001:470:ffff:ffff::/64
        {       
                AdvOnLink on;
                AdvAutonomous on;                                                                               
                AdvRouterAddr on;                                                                                       
        };
};

之后配置服务开机自起:

service radvd start

rc-update add radvd default

Gentoo中启动radvd 服务会自动开启ipv6 forwarding。

我的另一机器是 Centos 7,配置时需要手动在/etc/sysctl.con中加入:

net.ipv6.conf.default.forwarding=1
net.ipv6.conf.all.forwarding=1

 

配置ip6tables:

增加TUNNEL Chain,配置类似如下:

-A FORWARD -j TUNNEL

:TUNNEL - [0:0]
-A TUNNEL -s 2001:470:ffff:ffff::/64 -j ACCEPT
-A TUNNEL -d 2001:470:ffff:ffff::/64 -j ACCEPT
-A TUNNEL -s fe80::/10 -j ACCEPT
-A TUNNEL -d fe80::/10 -j ACCEPT
-A TUNNEL -j RETURN

之后在网络上接入其他设备,ping6 ipv6.google.com,测试无问题即可用。

 

相关链接:

Tunnel broker:

http://tunnelbroker.net/

Gentoo Wiki:

https://wiki.gentoo.org/wiki/IPv6_router_guide#Using_radvd

Gentoo + OpenRC 网络配置 PPPoE 双路网络

自家用的电信网络,允许4台客户机同时拨号,其中ADSL路由进行一次拨号提供家人的上网服务,同时使用花生壳的服务。自己的Pi拨号一次,给自己的网站一个地址,使用Dnspod的DDNS。

但默认网络的路由规则会导致所有出站的包都经由同一个默认路由,有两个线路的话其中一条会不可用,为了实现两个多个域名都能使用,要配置双路网络,加一个路由表:

其中ppp0通过eth0进行拨号,eth0为已配置好的局域网。

1、配置PPPoE:

Gentoo 中开启 ppp flag 后,portage 会自动安装需要的包。

在 /etc/portage/make.conf 中加入 ppp flag

USE="... ppp ..."

emergr 自动安装相关依赖包:

emerge --ask --changed-use --deep @world

2、相对的添加路由表

添加一个路由表,所有经由路由器(经由内网IP)的包会被使用新的路由表进行查询。

vim /etc/iproute2/rt_tables

添加:

...
#
# local
#
1       lan.inet

3、配置网络:

编辑 /etc/conf.d/net,添加对应规则,对应情况修改:

主要的是让eth0启动的时候在路由表中添加对应的规则,让对应的包使用新加的路由表。

config_eth0="<static lan ip here> netmask 255.255.255.0"
routes_eth0="default via 192.168.1.1 dev eth0 src <static lan ip here> table lan.inet"
rules_eth0="from <static lan ip here> lookup lan.inet"

dns_servers_eth0="192.168.1.1"

config_ppp0="ppp"
link_ppp0="eth0"
plugins_ppp0="pppoe"
username_ppp0='<username here>'
password_ppp0='<password here>'
pppd_ppp0="
noauth
defaultroute
usepeerdns
holdoff 3
child-timeout 60
lcp-echo-interval 15
lcp-echo-failure 3
noaccomp noccp nobsdcomp nodeflate nopcomp novj novjccomp"

rc_net_ppp0_need="net.eth0"

4、配置启动脚本:

开机自起:

cp /etc/init.d/net.lo /etc/init.d/net.ppp0

rc-update add net.ppp0 default

重启网络/系统,完成。

Defy 上重新分区并加入Kpanic分区

身边的Defy服役快5年了,3.7寸,1G+512内存小身板撑了这么久煞是不容易(还能再战十年!)

自己修改过内核的不少部分,稳定性现在不错,但如果偶遇内核Panic导致关机的话然后死的太突然并不能看到日志。而KPanic是Android上(曾经)常用的日志转储,在Kernel Panic的瞬间将日志转储到指定的分区上。我用的自定义分区表+内核似乎失去了这个功能。

通过刷上官方的固件之后用adb shell连过去,cat /proc/partitions看到:

179       32    1912832 mmcblk1
179       33        128 mmcblk1p1
179       34        512 mmcblk1p2
179       35        512 mmcblk1p3
179       36          1 mmcblk1p4
179       37        512 mmcblk1p5
179       38        512 mmcblk1p6
179       39       4096 mmcblk1p7      pds
179       40        512 mmcblk1p8
179       41        512 mmcblk1p9
179       42       1024 mmcblk1p10
179       43       2048 mmcblk1p11
179       44        512 mmcblk1p12
179       45        512 mmcblk1p13
179       46       4096 mmcblk1p14
179       47       8192 mmcblk1p15     boot
179       48       8192 mmcblk1p16     recovery
179       49      14336 mmcblk1p17     cdrom
179       50        512 mmcblk1p18     misc
179       51        512 mmcblk1p19     cid
179       52       4096 mmcblk1p20     kpanic
179       53     334848 mmcblk1p21     system
179       54        512 mmcblk1p22     prek
179       55        512 mmcblk1p23     pkbackup
179       56     204800 mmcblk1p24     cache
179       57    1319936 mmcblk1p25     userdata
179        0   61407232 mmcblk0
179        1   61406208 mmcblk0p1

查看原生分区的信息:

for i in /sys/block/mmcblk1/mmcblk1p*/; do
echo $i;
for j in `ls $i`; do
if [ -f $i$j ] ;then
echo "$j" : `cat $i$j`;
fi
done
done

得到了25个分区的start,end,size:

使用dd把整个/dev/mmcblk1 dump下来,使用16进制编辑器简单的看一下,可以在系统不可见分区里找到类似于分区表的东西,整理一下可看到整个Defy的分区结构,其中蓝色的是Android系统使用/可见的分区:

CONTENT DEV NODE START(BLOCK) SIZE(BLOCK) END(BLOCK)
mbmloader mmcblk1 256 256 512
mbm mmcblk2 1024 1024 2048
mbmbackup mmcblk3 2048 1024 3072
ebr mmcblk4 3072 2 3074
bploader mmcblk5 4096 1024 5120
cdt.bin mmcblk6 5120 1024 6144
pds mmcblk7 6144 8192 14336
lbl mmcblk8 14336 1024 15360
lbl_backup mmcblk9 15360 1024 16384
logo.bin mmcblk10 16384 2048 18432
sp mmcblk11 18432 4096 22528
devtree mmcblk12 22528 1024 23552
devtree_bak mmcblk13 23552 1024 24576
bpsw mmcblk14 24576 8192 32768
boot mmcblk15 32768 16384 49152
recovery mmcblk16 49152 16384 65536
cdrom mmcblk17 65536 28672 94208
misc mmcblk18 94208 1024 95232
cid mmcblk19 95232 1024 96256
kpanic mmcblk20 96256 8192 104448
system mmcblk21 104448 669696 774144
prek mmcblk22 774144 1024 775168
pkbackup mmcblk23 775168 1024 776192
cache mmcblk24 776192 409600 1185792
userdata mmcblk25 1185792 2639872 3825664

我之前一直在用的,XDA上大牛Quarx移植ROM所用的分区表,省去目前不考虑的分区:

PART DEV START(Byte) SIZE(Byte) END(Byte)
pds mmcblk1p9 3145728 4193792 7339520
root_system mmcblk1p1 53477376 51593216 105070592
system mmcblk1p5 105070593 657930240 763000833
system_sign mmcblk1p2 396221216 393216 396614432
prek1 mmcblk1p3 396361728 524288 396886016
prek2 mmcblk1p4 396886016 524288 397410304
cache mmcblk1p6 763000834 51200000 814200834
data mmcblk1p7 814200833 1143996416 1958197249

吐槽下这歪七扭八没对齐的分区数字,不过由于自定义分区是利用的Linux 内核一段时间前加的自定义MMC分区功能,并不会写到硬盘分区表,而内核在处理启动参数时候会自动对其,所以并没有性能的影响。

对其(为了方便计算)+重做一下分区,加入kpanic,新的分区表:

LABEL DEV START(Byte) SIZE(Byte) END(Byte)
pds mmcblk1p8 3145728 4194304 7340032
kpanic mmcblk1p9 49414144 4063232 53477376
bootstrap mmcblk1p1 53477376 33554432 87031808
system mmcblk1p5 87031808 671088640 758120448
system_sign mmcblk1p2 395968512 393216 396361728
prek mmcblk1p3 396361728 524288 396886016
pkbackup mmcblk1p4 396886016 524288 397410304
cache mmcblk1p6 758120448 50331648 808452096
userdata mmcblk1p7 808452096 1150287872 1958739968

Rom的BoardConfig中的BOARD_KERNEL_CMDLINE改成如下:

PARTITION_TABLE := blkdevparts=mmcblk1:33554432@53477376(root_system),393216@395968512(system_sign),524288@396361728(prek),524288@396886016(pkbackup),671088640@87031808(system),50331648@758120448(cache),1150287872@808452096(data),4194304@3145728(pds),4063232@49414144(kpanic) mmcparts=mmcblk1:p1(root_system),p2(system_sign),p3(prek),p4(pkbackup),p5(system),p6(cache),p7(data),p8(pds),p9(kpanic)
BOARD_RECOVERY_KERNEL_CMDLINE := console=/dev/null mem=499M init=/init omapfb.vram=0:4M usbcore.old_scheme_first=y cpcap_charger_enabled=y $(PARTITION_TABLE)
BOARD_KERNEL_CMDLINE := console=/dev/null panic=30 mem=499M init=/init ip=off brdrev=P3A omap3_die_id init=/init omapfb.vram=0:4M usbcore.old_scheme_first=y cpcap_charger_enabled=n $(PARTITION_TABLE)

由于要绕开Bootloader的检查使用自定义ROM,system覆盖了system_sign,system_sign是bootloader会去读取的数据,自定义ROM 通过设置badblock防止system分区的写操作破坏system_sign分区的内容。改动分区表之后badblock位置也变了,这次要将75424到75775设置为badblock。

之后修改Quarx的升级bootstrap和格式化用的刷机文件,主要修改Kernel cmdline和badblock,重新刷入,完成。

链接:

XDA上Quarx的ROM发布页:http://forum.xda-developers.com/showthread.php?t=2515036

我修改过的ROM:http://tieba.baidu.com/p/4061404066

Intel Galileo Gen 2 上运行带有 Arduino 兼容的 Debian

最近学校课设,用到了Intel Galileo Gen2,为了使用NodeJS开发安装了Galileo-Debian,之后遇到了两个问题,记录下:

1、安装Debian之后失去了原来的Arduino兼容功能。

2、安装Debian之后不停地pthread lib segfault。

添加Arduino兼容功能:

把Intel给的Yacto镜像解开看看,发现Yacto上开机自起/opt/cln/galileo,”监听”ttyGS0,负责Arduino部分的功能。

直接拿来用即可,不过Yacto用的似乎不是glibc,导致Debian中无法直接使用,为了省事直接把原镜像mount后chroot进去运行sketch即可,注意把 /dev 等涉及硬件操作的挂载点暴露给chroot。

注释掉/etc/inittab中的以下行,ttyGS0要交给shetch:

GS0:23:respawn:/sbin/getty -L ttyGS0 115200 vt100

把Intel提供的SDCard.1.0.4.tar.bz2解压,image-full-galileo-clanton.ext3放到sd卡的/opt/galileo-ketch/,Galileo开机执行以下脚本即可:

#!/bin/bash
dir="/opt/galileo-sketch"
mount $dir/image-full-galileo-clanton.ext3 $dir/mount
mount --rbind /dev $dir/mount/dev
mount --rbind /sys $dir/mount/sys
mount --rbind /proc $dir/mount/proc
mount --rbind /run $dir/mount/run
mount --rbind /tmp $dir/mount/tmp
nohup chroot $dir/mount /usr/bin/env HOME=/home/root PATH=/bin:/usr/bin:/sbin:/usr/sbin /bin/bash -c "source /etc/profile; /opt/cln/galileo/launcher.sh" &>/var/log/galileo-sketch.log &

F00F Bug

Google “debian galileo pthread segfault”后,发现有人遇到这问题了,原因是Intel Quark CPU有Bug,在F00F指令时触发。F0对应锁总线,而Galileo为单核设备,可以忽略这个操作,直接用十六进制编辑器吧F0替换成90(NOP),问题解决。

/lib/i386-linux-gnu/libpthread.so.0中所有的:

f0 0f b1 8b 94 21 00 00

替换为:

90 0f b1 8b 94 21 00 00

有其它f00f导致的segfault可以用类似方法解决。

 

相关链接:

Intel Galileo Support:http://www.intel.com/support/galileo/sb/CS-035101.htm

Galileo-Debian:http://sourceforge.net/projects/galileodebian/

Debian Bug:https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=738575