#250 Logrotate

2018-05-03

配置

# cat /etc/logrotate.conf
weekly
su root adm
rotate 4
create
#dateext
#compress
include /etc/logrotate.d

以 Nginx 配置为例:

# cat /etc/logrotate.d/nginx
/var/log/nginx/*.log {
        daily       # 按日切割
        missingok   # 如果文件不存在,则不创建
        rotate 14   # 最多保留 14 个日志文件
        compress    # 压缩
        delaycompress   # 延迟压缩
        notifempty      # 如果文件为空,则不创建
        create 0640 www-data adm

        # 可能一次切割多个日志,
        # 但是后面遇到的每个脚本都只执行一次,
        # 在所有日志切割之前或之后
        sharedscripts

        prerotate
                if [ -d /etc/logrotate.d/httpd-prerotate ]; then \
                        run-parts /etc/logrotate.d/httpd-prerotate; \
                fi \
        endscript

        postrotate
                invoke-rc.d nginx rotate >/dev/null 2>&1
        endscript
}

其他常用选项:

  • dateext 部分日志需要添加日期后缀
  • lastaction/endscript 最后执行的指令,很有用,比如最后将日志备份到某些地方

比如:

rsync -au *.gz 192.168.64.234:/backup/nginx-logs/`hostname -s`/

参考资料与拓展阅读

#249 关于 DNS(历史和未来)

2018-05-02

历史

从阿帕网 (ARPANET) 时代一直到互联网的早期,网络节点比较少,都是通过本地 hosts 文件来实现主机名到 IP 地址的映射。
根据维基百科的信息,斯坦福研究所负责维护了一个公共 hosts 文件,大家会找他同步 (rfc606, rfc608)。
PS: 这个时候如果有主机名重复了谁来管?打电话过去让他们改名?

这套机制一直运行了十几年,公共 hosts 文件已经变的很大了,变化也很频繁(IP 可能已经不再那么固定了),需要经常同步。这个时候,斯坦福研究所的网络压力也越来越大了。

后来人们开始设计域名和域名相关的公共设施 (rfc805, rfc830)。最后,在 1983 年,形成了下面两个 RFC 文档:

  • RFC 882, DOMAIN NAMES - CONCEPTS and FACILITIES
  • RFC 883, DOMAIN NAMES - IMPLEMENTATION and SPECIFICATION

几年后(1987),正式的 DNS 标准 RFC 1034 和 RFC 1035 推出。
这套标准一直运行到现在,可能有对其进行拓展(比如 DNS 记录类型不断添加,Unicode 字符引入),但是基本技术设计没有改变。

DNS 的管理权问题

https://zhidao.baidu.com/question/1386069665602139980.html

基本流程

比如本站域名 www.markjour.com, 其完整形式应该是 www.markjour.com. (后面多一个小数点)

DNS 软件

  • BIND
  • PowerDNS
  • dnsmasq
  • Unbound
  • CoreDNS
  • SmartDNS

Cache-Only DNS Server

新的发展

  1. 标准的 DNS 是运行在 UDP 53 端口上的。后来的 RFC 1123 增加了 TCP 的支持, 这个方案叫做 DNS over TCP, 还是在 53 端口。
  2. DNSCrypt, 2011 年设计的, 实现 DNS 的加密和验证,运行于 443 端口。注意:存在于 IETF 框架之外,但是好像有很多服务器支持。
  3. DNS over TLS (DoT), 2016 年 5 月成为规范。
    RFC 7858 Specification for DNS over Transport Layer Security (TLS)
    主要作用是加密传输,防止窃听。
  4. DNS over HTTPS (DoH), 2018 年 10 月成为规范。
    RFC 8484 DNS Queries over HTTPS (DoH)
    作用和 DoT 一样。
  5. DNS over TOR, 2019 年。
  6. Oblivious DNS-over-HTTPS (ODoH), 透过代理的方式,让 DoH 服务器无法获取客户端的真实 IP。同时代理无法获取 DNS 请求的内容。

参考资料与拓展阅读

#248 配置 Node 环境

2018-04-27
sudo apt install -y nodejs npm
# 已经不需要这句了:
# sudo ln -s `which nodejs` /usr/bin/node

# node -v
# npm -v

npm config set registry=https://registry.npm.taobao.org
sudo npm upgrade -g npm

# sudo npm install -g yarn --registry=https://registry.npm.taobao.org
curl --compressed -o- -L https://yarnpkg.com/install.sh | bash

yarn config set registry https://registry.npm.taobao.org

配置

echo registry=https://registry.npm.taobao.org > ~/.npmrc

npm config get registry
https://registry.npmjs.org/
npm config set registry=https://registry.npm.taobao.org

yarn config get registry
https://registry.yarnpkg.com
yarn config set registry https://registry.npm.taobao.org

#247 SMTP 拓展

2018-04-24

RFC#821 定义的 SMTP 协议非常简单(简陋)。
1993 年,RFC#1425 SMTP Service Extensions 定义了 SMTP 协议的拓展框架。
这个向前兼容的安全拓展框架是通过 EHLO 命令来实现。

#246 邮件发送中会遇到的各种地址

2018-04-16

注意:这边不是讨论 邮箱地址的格式

格式

  • 邮箱地址
  • "名称" <邮箱地址>

含义

  • SMTP 会话(投递)
  • Mail From 真实投递的发信人
  • Rcpt To 真实投递的收信人
  • 邮件内容(显示)
  • From 发信人
    • 如果和 Mail From 地址不同,可能会显示:由 xxx 代发
  • To 收信人
  • Cc 抄送人
  • Bcc 密送人
  • Rely-To 回复地址
    • 客户端点击回复的时候用的
    • 如果没有这个字段,就会回复 From 地址
  • Sender 发信人
  • Return-Path / Reverse-Path / Envelope-From
    • 作用是在邮件投递出现问题的时候,邮件服务将邮件退回这个地址
    • 如果我们看到这几个名字
    • 可能是发信人自己在邮件中声明
    • 可能是收信方收到邮件之后添加的,单独字段,或放在 Received 头中

关于抄送和密送

碳式复写纸 carbon paper
副本,抄送 carbon copy => CC
密送 blind carbon copy => BCC

按照设计,密送地址不希望被其他收信人、抄送人察觉,只是密送地址才知道自己是密送。

CC, BCC in SMTP

SMTP 服务器不处理 CC、BCC,SMTP 客户端应该自行处理
TO 地址 + CC 地址 + BCC 地址一起放到 SMTP 会话的 RCPT TO 字段

所以,按照我的理解,邮件客户端:

在一次 SMTP 会话中,如果有 3 个 TO/CC 地址,2 个 BCC 地址,应该对那 3 个地址批量发送,然后对那 2 个 BCC 地址分别加上 BCC 头,分别发送。
更稳妥一点:如果是批量发送邮件,不要放 BCC 到邮件头!!!显示一个 密送:xxx 也没啥意义。

  • PS:MSN(Outlook),网易邮箱发出去的邮件,不会加 BCC 头
    甚至网易可能在显示邮件原文的时候会移除 BCC 头(给网易邮箱发的 BCC 头都不见了)
  • PS:Gmail,QQ 邮箱发出去的邮件,密送人会看到 BCC 头
from_addr = "from@markjour.com"
to_addrs = ["to@markjour.com"]
cc_addrs = ["cc1@markjour.com", "cc2@markjour.com"]
bcc_addrs = ["bcc@markjour.com"]

msg = f"""
From: {from_addr}
To: {", ".join(to_addrs)}
Cc: {", ".join(cc_addrs)}

Hello World
""".strip()

send_to = to_addrs + cc_addrs + bcc_addrs

server = smtplib.SMTP('smtp.126.com')
server.set_debuglevel(1)
server.login(api_user, api_key)
server.sendmail(from_addr, send_to, msg)
server.quit()

#245 Python SMTP

2018-04-13
import logging
import smtplib
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart

logging.basicConfig(level=logging.DEBUG)

SMTP_HOST = 'smtp.example.com'
SMTP_PORT = 587
SMTP_USERNAME = 'your_username'
SMTP_PASSWORD = 'your_password'
SMTP_STARTTLS = True

sender = 'sender@example.com'
recipients = ['rcpt01@example.com', '中国 <rcpt02@example.com>']
subject = 'Test Email'
content_text = 'This is a test email.'
content_html = '<html><h1>Hello</h1></html>'


def encode_recipient(name, addr):
    pass


msg = MIMEMultipart()
msg['From'] = sender
msg['To'] = ', '.join(recipients)
msg['Subject'] = subject
msg.attach(MIMEText(content_text))
msg.attach(MIMEText(content_html))
print(msg.as_string())


def smtp_debug(self, *args):
    msg = ' '.join(map(str, args))
    logging.debug(msg)


smtp = smtplib.SMTP(SMTP_HOST, SMTP_PORT)
smtp._print_debug = smtp_debug
smtp.set_debuglevel(1)
smtp.ehlo()
if SMTP_STARTTLS:
    smtp.starttls()
    smtp.ehlo()
if SMTP_USERNAME and SMTP_USERNAME:
    smtp.login(SMTP_USERNAME, SMTP_PASSWORD)

smtp.sendmail(sender, recipients, msg.as_string())
smtp.quit()

#244 邮件中的时间格式

2018-04-10

比如:

Sun, 20 Jun 2018 00:47:04 -0700 (PDT)
Thu, 10 Jun 2021 16:10:03 -0700 (PDT)
Thu, 10 Jun 2021 08:06:31 -0700 (PDT)

定义

定义在 RFC 822 的 5. DATE AND TIME SPECIFICATION

date-time   =  [ day "," ] date time        ; dd mm yy hh:mm:ss zzz
day         =  "Mon"  / "Tue" /  "Wed"  / "Thu" /  "Fri"  / "Sat" /  "Sun"
date        =  1*2DIGIT month 2DIGIT        ; day month year e.g. 20 Jun 82
month       =  "Jan"  /  "Feb" /  "Mar"  /  "Apr" /  "May"  /  "Jun" /  "Jul"  /  "Aug" /  "Sep"  /  "Oct" /  "Nov"  /  "Dec"
time        =  hour zone                    ; ANSI and Military
hour        =  2DIGIT ":" 2DIGIT [":" 2DIGIT]
                                            ; 00:00:00 - 23:59:59
zone        =  "UT"  / "GMT"                ; Universal Time
                                            ; North American : UT
            /  "EST" / "EDT"                ;  Eastern:  - 5/ - 4
            /  "CST" / "CDT"                ;  Central:  - 6/ - 5
            /  "MST" / "MDT"                ;  Mountain: - 7/ - 6
            /  "PST" / "PDT"                ;  Pacific:  - 8/ - 7
            /  1ALPHA                       ; Military: Z = UT;
                                            ;  A:-1; (J not used)
                                            ;  M:-12; N:+1; Y:+12
            / ( ("+" / "-") 4DIGIT )        ; Local differential
                                            ;  hours+min. (HHMM)

总结就是:

[day-of-week,] day month year hour:minute[:second] timezone
  1. 周几和秒是可选的,据我观察,没有邮件省略这两部分
  2. 周几和月份采用三字母英文缩写(首字母大写)
  3. 年份是 2 位数字,后来的规范更新中建议采用 4 位数字。出于兼容性考虑,一般都保留了对 RFC 822 两位数字年份的支持。
  4. 时区除了数字之外,可以使用 UTGMTESTEDTCSTCDTMSTMDTPSTPDT
    还有 25 个字母(J 没有使用),Z 表示 UTC/GMT 时间,A - M 表示 -1 ~ -12 时区,N - Y 表示 1 到 12 时区。
  1 2 3 4 5 6 7 8 9 10 11 12
West A B C D E F G H I K L M
Eest N O P Q R S T U V W X Y

Python

生成符合要求的时间字符串比较简单:

import time
time.strftime('%a, %d %b %Y %H:%M:%S %z')
# 'Tue, 10 Apr 2018 09:10:05 +0800'

但是由于这个灵活度比较大,解析起来最好借助专业的库(email.utils)来做这个事。

import time
import datetime
import email.utils
import pytz

# 解析 ############################################

date_str = 'Sun, 20 Jun 2018 00:47:04 -0700 (PDT)'
email.utils.parsedate_to_datetime(date_str)
# datetime.datetime(2018, 6, 20, 0, 47, 4, tzinfo=datetime.timezone(datetime.timedelta(days=-1, seconds=61200)))
email.utils.parsedate_tz(date_str)
(2018, 6, 20, 0, 47, 4, 0, 1, -1, -25200)

# 生成 ############################################

# email.utils.formatdate(timeval=None, localtime=False, usegmt=False)
email.utils.formatdate()
# 'Tue, 10 Apr 2018 09:10:41 -0000'

# email.utils.format_datetime(dt, usegmt=False)
dt = datetime.datetime.now()
email.utils.format_datetime(dt)
# 'Tue, 10 Apr 2018 09:16:43 -0000'

tz = pytz.timezone('Asia/Shanghai') # <DstTzInfo 'Asia/Shanghai' LMT+8:06:00 STD>
dt = datetime.datetime(2018, 4, 10, 9, 10, 0, tzinfo=tz)
# datetime.datetime(2018, 4, 10, 9, 10, tzinfo=<DstTzInfo 'Asia/Shanghai' LMT+8:06:00 STD>)
email.utils.format_datetime(dt)
# 'Tue, 10 Apr 2018 09:10:00 +0806'

#243 邮箱地址的格式

2018-04-07

规范

规范定义比较复杂,甚至支持注释。

我简化一下(去掉注释,去掉双引号,去掉 [IPv4] / [IPv6] / 主机名 做域):

  1. 格式:域内部分@域
  2. 域内部分:

  3. 长度不超过 64

  4. 大小写字母 + 数字(62)
  5. ASCII 标点符号(19)

    !#$%&'*+-/=?^_`{|}~
    
  6. 可以加入点号(.)隔开,不放首尾,不连续出现

  7. 域名

  8. 每一级域名 1 - 63 个字符,总长度不超过 253
    这个限制和 DNS 报文设计有关
    国际化域名转换成 Punycode 之后也必须遵守这个约定

  9. 允许包含数字、字母(大小写不敏感)和短横线(-
  10. 短横线不能出现在首尾位置

实践

实际上的邮件地址会更加简单:

  1. 长度限制
  2. QQ 邮箱 3 - 18
  3. 网易邮箱 6 - 18
  4. Gmail 6 - 30
  5. 新浪邮箱 4 - 16
  6. 字符限制:字母数字 + .-_
  7. 一般大小写不敏感
  8. 连字符(.-_)不可连续出现
    1. 网易免费邮箱只支持下划线,网易 VIP 邮箱支持点和下划线
    2. Gmail 只支持点和加号
      1. 在实际投递中,点和加号会被忽略
      2. 点可以用作单词风格
      3. 加号通常用做来信归类,比如注册淘宝时 +taobao,订阅开发者头条时 +toutiao,相关邮件就方便搜索归类。
  9. 部分邮箱不支持全数字(别有用途,或是避免 QQ 号冲突,或是避免手机号冲突)
  10. 开头结尾字符限制:
    1. 字母数字开头 + 字母数字结尾
    2. 字母开头 / 字母数字结尾

正则表达式

以规范为准,参考真实场景下的实践:

域内部分:

/[a-z0-9]+([.-_#][a-z0-9]+)+/;

域名部分:

/[a-z0-9]+(-[a-z0-9]+)?(\.[a-z0-9]+(-[a-z0-9]+)?)+/;

汇总在一起就是:

/^[a-z0-9]+([.-_#][a-z0-9]+)+@[a-z0-9]+(-[a-z0-9]+)?(\.[a-z0-9]+(-[a-z0-9]+)?)+$/;

参考资料与拓展阅读

#242 OpenStack 相关网络技术

2018-03-24

相关文章:

物理设备

  1. VLAN 虚拟局域网,设备层面上的网络分区,网络设备提供的功能
    网络报文给 VLAN Tag 分配了四个字节,其中 3 个字节用于 VLAN ID,1 个字节用于 VLAN Priority。
    作为 VLAN ID 的 12bit(0-4095)中,首位两数作为保留值,也就是说 VLAN 技术支持的最大网络数是 4094。

Linux 网络技术

在 Linux 内核的网络设备管理层,虚拟设备和物理设备是同等地位。

  1. network namespace 网络隔离,虚拟化的基础
  2. bridge 网桥,相当于交换机,二层数据交换
  3. veth 虚拟网口,成对出现,两个虚拟网口之间可以相互连接(可以跨 namespace)
  4. tap/tun
  5. tap TAP 设备,虚拟二层网络,处理 TCP/UDP 包,
    有自己的 MAC 地址,可以桥接到物理网卡
  6. tun TUN 设备,虚拟三层网络,处理 IP 包
  7. iptables 网络管理
    确切的说是以 iptables 为代表的一系列网络管理技术

KVM / Neutron

  1. qvb neutron 网络桥
  2. qvo neutron 网络虚拟接口

Neutron 网络模式:

  1. VLAN
  2. VXLAN 虚拟拓展局域网,在三层 UDP 协议中封装二层数据包,突破 VLAN 的限制
  3. GRE Gerneral Routing Encapsulation,通用路由封装协议

#241 英语单词类别(词性)

2018-03-18
类别 英语名称 简写 说明
名词 noun n -
动词 verb v -
形容词 adjective adj -
副词 adverb ad/adv -
介词 preposition perp in on at
连词 conjunction conj and or but if
代词 pronoun pron I you he she
数词 numeral num one two three
冠词 article art the a an
感叹词 interjection interj oh hey
  • 名词:
    • 专有名词
    • 普通名词(可数/不可数);
      • 个体
      • 集体
      • 物质
      • 抽象
  • 冠词:不定冠词,定冠词,零冠词;
  • 数词:基数词,序数词;