Send IP Address to Mailbox

Send IP address to mailbox to get remote address everywhere all at once. Modified: 2023-07-15 09:20:55 Created: 2021-08-22 09:50:08 Tags: #intranet penetration #linux #cron

有一台 linux 服务器,运营商提供了公网ipv6地址,在外面可以通过 ssh 访问。 公网ipv6地址偶尔也会变,给访问造成了巨大的麻烦。为了实现在外部可靠ssh访问服务器的目标,通常有两种思路:

  • 动态端口映射(DDNS):将服务器端口映射到有公网ip地址的远程机器端口上。通过远程机器的公网ip地址访问。带有公网ip地址的云服务器的体验套餐比较便宜,可以实现。
  • 服务器获取ipv6地址,发送到指定邮箱,实现起来方便快捷,是本文要介绍的内容。

linux 服务器自动发送ipv6地址到指定邮箱需要经过三个过程:

  1. 用 python 获取本机ip地址
  2. smtp发送邮件(而不是登陆邮箱点发送按钮)
  3. crond让整个过程自动化

1. 用 python 获取本机ip地址

使用ipconfigip addr可以获取本机ip地址:

通过ip addr命令查看ip,其中红框inet6就是我们需要的ipv6地址。 内网ip地址是192.168.1.6。实际上也可以用这种方式获取本机ip地址。python 有 subprocessos这样的包,可以运行shell 脚本,获取输出。为了得到真正想要的ip地址,还需要比较复杂的字符串处理。选择优雅socket包:

import socket
def get_ip():
    hostname = socket.gethostname()
    addr_infos = socket.getaddrinfo(hostname, None)
    ips = set([addr_info[-1][0] for addr_info in addr_infos])
    global_ips = [ip for ip in ips if ip.startswith("24")]
    return global_ips

socket会获取所有的ip地址,但需要的是公网ipv6。公网ipv6一般是以24开头。这里加了一个筛选。获取的结果是一个list,每个元素是ipv6地址的字符串。

2. 用 smtp 发送邮件

使用 python 的smtp包发送邮件,需要一个支持smtp的邮箱(常见的邮箱都支持smtp),以sina.com邮箱为例:

import smtplib
from email.header import Header
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
from time import asctime

def send_an_email(email_content): # email_content是一个字符串
    mail_host = "smtp.sina.com" # 这个去邮箱找,这里用的sina邮箱
    mail_user = 发送的邮箱地址
    mail_auth_code = 授权码不是邮箱的登陆密码
    mail_sender = mail_user # 用mail_user 作为发送人
    mail_receivers = [收件人list]
    message = MIMEMultipart()
    message['From'] = Header(mail_sender)  # 寄件人
    message['Subject'] = Header("主题名字")
    message.attach(MIMEText(asctime(), 'plain', 'utf-8'))
    message.attach(MIMEText(email_content, 'plain', 'utf-8'))
    print("message is {}".format(message.as_string())) # debug用
    smtpObj = smtplib.SMTP(mail_host)
    # smtpObj.set_debuglevel(1) # 同样是debug用的
    smtpObj.login(mail_user, mail_auth_code) # 登陆
    smtpObj.sendmail(mail_sender, mail_receivers, message.as_string()) # 真正发送邮件就是这里

登陆自己的邮箱,找到设置,找到客户端 pop/imap/smtp。从这里找到smtp服务器的地址,以及生成授权码。

这里会看到授权码。(由于我之前是申请过了的,所以这里是重置。)如果没有的话,则是要你申请,在邮箱设置里面获得授权码。

将邮箱配置好之后,可以调用这个send_an_email函数。自己修改email_contentHeader,查看发送效果。

通过smtp发送了一封邮件。

3. 自动化这个过程

虽然我们实现了自动获取ip地址,也实现了通过 python 的smtp包进行邮件发送。但是离智能还是差一点:所有过程都得人工去运行这个脚本。我们希望的是:ipv6地址一旦变化,就给我发邮件,但是又不要时时刻刻给我发邮件。 实现思路是监控服务器的ipv6地址,将当前的ipv6地址存储下来,每隔一个固定时间就检查一下服务器ipv6地址,如果没有变化,则不发送邮件,如果有变化,则发送邮件。按照这个思路对获取ipv6地址的代码进行改造:

def get_temp_ip(current_ip):
    temp_ip_json_path = "/var/tmp/ip.json"
    if not os.path.exists(temp_ip_json_path):
        print("No {}, dump it.".format(temp_ip_json_path))
        with open(temp_ip_json_path, 'w') as jo:
            json.dump(current_ip, jo)
            return True, current_ip
    else:
        with open(temp_ip_json_path, 'r') as jo:
            origin_ip = json.load(jo)
        if origin_ip == current_ip:
            print("Current ip {} do not change, no need to send".format(current_ip))
            return False, current_ip
        else:
            print("The ip updated from {} to {}, update it.".format(origin_ip, current_ip))
            os.remove(temp_ip_json_path)
            with open(temp_ip_json_path, 'w') as jo:
                json.dump(current_ip, jo)
                return True, current_ip


def get_ip():
    hostname = socket.gethostname()
    addr_infos = socket.getaddrinfo(hostname, None)
    ips = set([addr_info[-1][0] for addr_info in addr_infos])
    global_ips = [ip for ip in ips if ip.startswith("24")]
    whether_to_send, send_ip = get_temp_ip(global_ips)
    send_ip = json.dumps(send_ip)
    return whether_to_send, send_ip

先判断是否有/var/tmp/ip.json文件。如没有就将当前ipv6地址保存,且发送邮件。如存在就读取其中的ipv6地址,若当前ipv6和保存的ipv6地址一样,就继续等待下一次检查,如不一样就更新ip.json文件并且发送邮件。通常还要给脚本添加上main

if __name__ == "__main__":
    whether_to_send, global_ips = get_ip()
    if whether_to_send:
        send_an_email(global_ips)
    else:
        print("wait and no send")

给脚本添加上可执行权限:

sudo chmod +x send_ip_to_mailbox.py

使用 linux 的排程工具crond将任务排期自动执行,这里配置的是每隔 1 分钟执行一次ipv6地址检查。

# 在/etc/cron.d/下面建立一个空白文件
sudo vim /etc/cron.d/ipsync
# 内容如下
*/1 * * * * chinglin /abs_path_to_send_ip_to_mailbox.py

启动crond

sudo systemctl restart crond # 启动
sudo systemctl enable crond # 设定开机启动

至此,可以用邮箱收取服务器的ipv6地址了。

总结

本文主要介绍自动将linux服务器ip地址发送到指定邮箱的方式。基本步骤是用socket获取ipv6地址,用smtp发送邮件,用crond自动化运行。