dip(Dial-up IP)是一个用于建立拨号IP连接的Linux工具,主要用于通过调制解调器(Modem)建立PPP(点对点协议)或SLIP(串行线路网际协议)连接。虽然现在宽带网络普及,但在某些特定场景(如远程监控、工业控制、备份连接)中仍有使用。
pppd(PPP守护进程)和wvdial进行拨号连接。但在嵌入式系统或特定应用场景中仍可能遇到。
# 基本格式
dip [选项] [脚本文件]
# 常用格式
dip -t # 测试模式
dip -v # 详细模式
dip -p ppp # 使用PPP协议
dip -i # 交互模式
dip 配置文件.dip # 执行拨号脚本
在大多数Linux发行版中,dip可能没有预装,需要手动安装:
# Debian/Ubuntu
sudo apt-get update
sudo apt-get install dip
# RHEL/CentOS 7及之前版本
sudo yum install dip
# 或
sudo dnf install dip # RHEL/CentOS 8+
# Arch Linux
sudo pacman -S dip
# 从源码编译安装
wget http://ftp.debian.org/debian/pool/main/d/dip/dip_3.3.7o.orig.tar.gz
tar -xzvf dip_3.3.7o.orig.tar.gz
cd dip-3.3.7o
make
sudo make install
# 验证安装
dip -v
which dip
# 输出示例:/usr/sbin/dip
dip使用自己的脚本语言来定义拨号过程,主要命令包括:
| 命令 | 描述 |
|---|---|
port |
指定串行端口(如/dev/ttyS0) |
speed |
设置端口速率(如115200) |
modem |
指定调制解调器类型(如HAYES) |
dial |
拨号命令,后接电话号码 |
wait |
等待指定文本(如"CONNECT") |
send |
发送字符串到调制解调器 |
get $local |
获取本地IP地址 |
get $remote |
获取远程IP地址 |
default |
设置默认网关 |
mode |
设置协议模式(PPP/SLIP) |
goto |
跳转到标签 |
if |
条件判断 |
exit |
退出脚本 |
# |
注释符号 |
创建一个简单的拨号脚本:
# 文件名: connect.dip
# 注释:基本拨号脚本示例
# 设置串行端口
port /dev/ttyS0
# 设置波特率
speed 115200
# 设置调制解调器类型
modem HAYES
# 重置调制解调器
reset
# 发送AT命令测试调制解调器
send "ATZ\r"
wait OK 2
if $errlvl != 0 goto error
# 拨号
send "ATDT1234567\r"
wait CONNECT 60
if $errlvl != 0 goto error
# 连接成功,设置协议
mode PPP
# 获取IP地址
get $local 0.0.0.0
get $remote 0.0.0.0
# 设置默认网关
default
# 退出脚本
exit 0
# 错误处理标签
error:
print "拨号失败,错误代码: $errlvl"
exit 1
# 保存后执行
# sudo dip connect.dip
创建完整的PPP连接脚本:
# 文件名: ppp-connect.dip
# 完整的PPP拨号连接脚本
# 配置串行端口
port /dev/ttyS0
speed 57600
modem HAYES
# 调试信息
echo "开始拨号连接..."
# 初始化调制解调器
send "ATZ\r"
wait OK 5
if $errlvl != 0 goto modem_error
# 设置调制解调器参数
send "ATE0V1Q0\r" # 关闭回显,开启详细响应,关闭结果码
wait OK 2
if $errlvl != 0 goto modem_error
# 检查调制解调器状态
send "ATI\r"
wait OK 2
# 拨号
echo "正在拨号 1234567..."
send "ATDT1234567\r"
# 等待连接
wait CONNECT 30
if $errlvl != 0 goto dial_error
echo "连接建立成功,协商PPP参数..."
# 切换到PPP模式
mode PPP
# 设置PPP参数
# 不使用压缩
send "ppp neg vj off\r"
# 设置MRU
send "ppp neg mru 1500\r"
# 禁用PAP/CHAP认证(如果需要)
# send "ppp neg auth off\r"
# 获取IP地址
echo "获取IP地址..."
get $local 0.0.0.0
get $remote 0.0.0.0
# 显示IP信息
echo "本地IP: $local"
echo "远程IP: $remote"
# 设置路由
default
add 0.0.0.0 gw $remote
echo "PPP连接建立完成!"
exit 0
# 错误处理
modem_error:
echo "调制解调器初始化失败"
exit 1
dial_error:
echo "拨号失败,请检查电话号码和线路"
exit 2
# 保存后执行
# sudo dip -v ppp-connect.dip
在交互模式下使用dip:
# 启动dip交互模式
sudo dip -i
# dip交互命令行提示符 DIP>
# 可以执行各种命令:
DIP>port /dev/ttyS0
DIP>speed 115200
DIP>modem HAYES
DIP>reset
DIP>send "ATZ\r"
DIP>wait OK 5
# 显示等待结果
DIP>print $errlvl
DIP>send "ATDT1234567\r"
DIP>wait CONNECT 30
DIP>mode ppp
DIP>get $local
DIP>get $remote
DIP>default
DIP>exit
# 交互模式下也可以使用变量
DIP>set $myvar 10
DIP>print $myvar
# 输出: 10
# 条件判断
DIP>if $errlvl == 0 goto success
DIP>print "错误发生"
DIP>goto end
DIP>success:
DIP>print "操作成功"
DIP>end:
# 查看帮助
DIP>help
# 或
DIP>?
创建自动检测和重连的脚本:
#!/bin/bash
# 文件名: auto-reconnect.sh
# 自动拨号连接和重连脚本
CONFIG_FILE="/etc/dip/ppp-connect.dip"
LOG_FILE="/var/log/dip-connection.log"
MAX_RETRIES=5
RETRY_DELAY=30
# 记录日志函数
log_message() {
echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" >> $LOG_FILE
echo "$1"
}
# 检查连接状态函数
check_connection() {
# ping测试连接
ping -c 2 -W 3 8.8.8.8 > /dev/null 2>&1
return $?
}
# 建立连接函数
establish_connection() {
log_message "尝试建立拨号连接..."
# 检查调制解调器是否存在
if [ ! -c /dev/ttyS0 ]; then
log_message "错误: 串行设备 /dev/ttyS0 不存在"
return 1
fi
# 检查dip是否安装
if ! command -v dip &> /dev/null; then
log_message "错误: dip命令未找到,请先安装dip"
return 1
fi
# 启动dip连接
dip -v $CONFIG_FILE >> $LOG_FILE 2>&1
if [ $? -eq 0 ]; then
log_message "连接建立成功"
return 0
else
log_message "连接建立失败"
return 1
fi
}
# 断开连接函数
disconnect() {
log_message "断开现有连接..."
# 查找dip进程
DIP_PID=$(ps aux | grep "dip" | grep -v grep | grep -v auto-reconnect | awk '{print $2}')
if [ -n "$DIP_PID" ]; then
kill -TERM $DIP_PID
sleep 5
# 强制杀死如果仍在运行
if ps -p $DIP_PID > /dev/null 2>&1; then
kill -KILL $DIP_PID
fi
log_message "连接已断开"
fi
# 重置串行端口
if [ -c /dev/ttyS0 ]; then
stty -F /dev/ttyS0 sane
fi
return 0
}
# 主程序
log_message "=== 自动拨号连接脚本启动 ==="
log_message "配置文件: $CONFIG_FILE"
log_message "最大重试次数: $MAX_RETRIES"
RETRY_COUNT=0
CONNECTED=false
while true; do
# 检查当前连接状态
if check_connection; then
if [ "$CONNECTED" = false ]; then
log_message "连接正常"
CONNECTED=true
fi
else
if [ "$CONNECTED" = true ]; then
log_message "连接丢失"
CONNECTED=false
fi
# 断开旧连接
disconnect
# 尝试建立新连接
while [ $RETRY_COUNT -lt $MAX_RETRIES ]; do
log_message "重试连接 ($((RETRY_COUNT+1))/$MAX_RETRIES)"
if establish_connection; then
CONNECTED=true
RETRY_COUNT=0
break
else
RETRY_COUNT=$((RETRY_COUNT+1))
if [ $RETRY_COUNT -lt $MAX_RETRIES ]; then
log_message "等待 $RETRY_DELAY 秒后重试..."
sleep $RETRY_DELAY
else
log_message "达到最大重试次数,等待5分钟后继续..."
sleep 300
RETRY_COUNT=0
fi
fi
done
fi
# 等待一段时间后再次检查
sleep 60
done
dip与pppd配合使用的配置:
# dip负责拨号,pppd负责PPP协议处理
# 文件名: dip-pppd.sh
# 创建dip拨号脚本
cat > /etc/dip/dial.dip << 'EOF'
port /dev/ttyS0
speed 115200
modem HAYES
reset
send "ATZ\r"
wait OK 5
if $errlvl != 0 goto error
send "ATDT1234567\r"
wait CONNECT 30
if $errlvl != 0 goto error
# 不进入PPP模式,将控制权交给pppd
mode ppp
exit 0
error:
print "拨号失败"
exit 1
EOF
# 创建pppd配置文件
cat > /etc/ppp/peers/myisp << 'EOF'
/dev/ttyS0
115200
noauth
defaultroute
noipdefault
usepeerdns
persist
maxfail 0
holdoff 5
connect "/usr/sbin/dip /etc/dip/dial.dip"
EOF
# 创建PAP认证文件(如果需要)
cat > /etc/ppp/pap-secrets << 'EOF'
# 用户名 服务 密码 IP地址
myuser * mypass *
EOF
# 创建CHAP认证文件(如果需要)
cat > /etc/ppp/chap-secrets << 'EOF'
# 用户名 服务 密码 IP地址
myuser * mypass *
EOF
# 启动pppd连接
sudo pppd call myisp
# 查看连接状态
ifconfig ppp0
route -n
# 查看pppd日志
tail -f /var/log/messages | grep pppd
tail -f /var/log/syslog | grep pppd
# 断开连接
sudo poff myisp
# 或
sudo killall pppd
dip连接故障排查:
# 1. 检查串行端口
ls -la /dev/ttyS*
# 查看当前用户是否有访问权限
ls -la /dev/ttyS0
# 如果没有权限,需要添加用户到dialout组
sudo usermod -a -G dialout $USER
# 或使用sudo运行dip
# 2. 测试串行端口
sudo stty -F /dev/ttyS0
# 查看当前设置
sudo stty -F /dev/ttyS0 115200
# 设置波特率
echo "ATZ" | sudo tee /dev/ttyS0
# 测试发送AT命令
# 3. 查看调制解调器响应
sudo cat < /dev/ttyS0 &
# 在另一个终端发送命令
echo "ATZ" | sudo tee /dev/ttyS0
# 应该看到"OK"响应
# 4. 使用dip测试模式
sudo dip -t connect.dip
# 显示命令但不执行
# 5. 使用dip详细模式
sudo dip -v connect.dip
# 显示详细信息
# 6. 检查调制解调器日志
# 创建详细的dip脚本
cat > debug.dip << 'EOF'
port /dev/ttyS0
speed 115200
modem HAYES
debug 255
reset
send "ATZ\r"
wait OK 5
print "errlvl=$errlvl"
send "ATI\r"
wait OK 2
print "调制解调器信息显示完成"
exit
EOF
sudo dip debug.dip
# 7. 检查系统日志
dmesg | grep ttyS
tail -f /var/log/syslog | grep dip
journalctl -f | grep dip
# 8. 使用minicom进行手动测试
sudo apt-get install minicom # Debian/Ubuntu
sudo yum install minicom # RHEL/CentOS
# 配置minicom
sudo minicom -s
# 选择Serial port setup
# 设置串行设备: /dev/ttyS0
# 设置波特率: 115200
# 保存为默认配置
# 退出并启动minicom
# 在minicom中手动测试AT命令
# ATZ
# ATDT1234567
# 观察响应
# 9. 检查调制解调器硬件
# 确保调制解调器正确连接
# 检查电缆和电源
# 尝试不同的串行端口
# 10. 检查电话号码和ISP设置
# 确认电话号码正确
# 确认ISP不需要特殊拨号前缀
# 确认账户有效
pppd (PPP守护进程)功能更强大的PPP实现,支持更多协议和功能。
# 安装pppd
sudo apt-get install ppp
# 配置
sudo nano /etc/ppp/peers/myisp
# 启动
sudo pppd call myisp
# 断开
sudo poff myisp
wvdial智能PPP拨号器,自动检测和配置调制解调器。
# 安装wvdial
sudo apt-get install wvdial
# 自动检测配置
sudo wvdialconf
# 编辑配置
sudo nano /etc/wvdial.conf
# 拨号
sudo wvdial
# 查看状态
sudo wvdial -s
chat与调制解调器交互的脚本工具,常与pppd配合使用。
# 安装chat
sudo apt-get install ppp
# 使用示例
sudo chat -v -f chat.script
# chat脚本示例:
# ABORT BUSY
# ABORT "NO CARRIER"
# TIMEOUT 10
# "" ATZ
# OK ATDT1234567
# CONNECT ""
NetworkManager现代Linux网络管理工具,支持多种连接类型。
# 图形界面配置
nm-connection-editor
# 命令行管理
nmcli connection show
nmcli connection up "My Dial-up"
# 添加拨号连接
nmcli connection add type gsm ifname ttyUSB0
dip |
pppd |
|---|---|
| 较老的拨号工具 | 功能完整的PPP守护进程 |
| 包含自己的脚本语言 | 使用配置文件或chat脚本 |
| 同时处理拨号和PPP | 专注于PPP协议处理 |
| 功能相对简单 | 支持更多PPP特性和协议 |
| 适合简单拨号连接 | 适合复杂网络环境 |
| 逐渐被淘汰 | 现代Linux的标准PPP工具 |
建议:新项目建议使用pppd,dip仅用于维护旧系统。
# 方法1: 使用init.d脚本(System V)
sudo nano /etc/init.d/dip-connect
# 内容:
#!/bin/bash
# chkconfig: 345 99 01
# description: 自动拨号连接
case "$1" in
start)
/usr/sbin/dip /etc/dip/connect.dip
;;
stop)
killall dip
;;
restart)
killall dip
sleep 2
/usr/sbin/dip /etc/dip/connect.dip
;;
*)
echo "用法: $0 {start|stop|restart}"
exit 1
;;
esac
exit 0
# 设置权限
sudo chmod +x /etc/init.d/dip-connect
# 启用开机启动
sudo chkconfig --add dip-connect
sudo chkconfig dip-connect on
# 方法2: 使用systemd服务(现代系统)
sudo nano /etc/systemd/system/dip-connect.service
# 内容:
[Unit]
Description=Dial-up Connection via dip
After=network.target
[Service]
Type=forking
ExecStart=/usr/sbin/dip /etc/dip/connect.dip
ExecStop=/usr/bin/killall dip
Restart=on-failure
RestartSec=5s
[Install]
WantedBy=multi-user.target
# 启用服务
sudo systemctl daemon-reload
sudo systemctl enable dip-connect.service
sudo systemctl start dip-connect.service
# 方法3: 使用crontab
sudo crontab -e
# 添加:
@reboot sleep 30 && /usr/sbin/dip /etc/dip/connect.dip
# 方法4: 在/etc/rc.local中添加
sudo nano /etc/rc.local
# 在exit 0之前添加:
sleep 30
/usr/sbin/dip /etc/dip/connect.dip
exit 0
# 注意:确保rc.local有执行权限
sudo chmod +x /etc/rc.local
$errlvl是dip脚本中的错误级别变量,表示最近命令的执行结果:
0: 成功1: 超时(wait命令)2: 收到不期望的响应3: 其他错误# 示例:使用$errlvl进行错误处理
send "ATZ\r"
wait OK 5
if $errlvl != 0 goto modem_error
send "ATDT1234567\r"
wait CONNECT 30
if $errlvl == 1 goto timeout_error
if $errlvl == 2 goto unexpected_response
if $errlvl == 3 goto other_error
# 成功继续
goto success
modem_error:
print "调制解调器错误: $errlvl"
exit 1
timeout_error:
print "连接超时"
exit 2
unexpected_response:
print "收到意外响应"
exit 3
other_error:
print "其他错误: $errlvl"
exit 4
success:
print "连接成功"
exit 0
# 也可以使用switch-case风格的判断
# dip不支持switch,但可以用if-elseif实现
if $errlvl == 0 goto case0
if $errlvl == 1 goto case1
if $errlvl == 2 goto case2
if $errlvl == 3 goto case3
goto default
case0:
print "成功"
goto end
case1:
print "超时"
goto end
case2:
print "意外响应"
goto end
case3:
print "其他错误"
goto end
default:
print "未知错误"
goto end
end:
调试步骤:
dip -v script.dipdip -t script.dip(不执行)print命令tail -f /var/log/syslogminicom或cu测试调制解调器/dev/ttyS*有读写权限# 最小测试脚本
cat > test.dip << 'EOF'
port /dev/ttyS0
speed 115200
modem HAYES
debug 255
print "开始测试..."
send "ATZ\r"
wait OK 5
print "errlvl=$errlvl"
if $errlvl == 0 print "调制解调器正常"
if $errlvl != 0 print "调制解调器异常"
exit
EOF
sudo dip -v test.dip
# 添加更多调试
cat > debug.dip << 'EOF'
# 详细调试脚本
port /dev/ttyS0
print "端口设置完成"
speed 115200
print "波特率设置完成"
modem HAYES
print "调制解调器类型设置完成"
debug 255
print "调试级别设置完成"
print "发送ATZ命令..."
send "ATZ\r"
print "等待OK响应..."
wait OK 5
print "等待完成,errlvl=$errlvl"
print "发送ATI命令..."
send "ATI\r"
print "等待调制解调器信息..."
wait OK 2
print "调制解调器信息完成"
print "脚本执行结束"
exit
EOF
sudo dip debug.dip 2>&1 | tee dip-debug.log