linux dip命令

命令简介

dip(Dial-up IP)是一个用于建立拨号IP连接的Linux工具,主要用于通过调制解调器(Modem)建立PPP(点对点协议)或SLIP(串行线路网际协议)连接。虽然现在宽带网络普及,但在某些特定场景(如远程监控、工业控制、备份连接)中仍有使用。

注意:dip是较老的拨号连接工具,现代Linux系统中更多使用pppd(PPP守护进程)和wvdial进行拨号连接。但在嵌入式系统或特定应用场景中仍可能遇到。

基本语法

# 基本格式
dip [选项] [脚本文件]

# 常用格式
dip -t                     # 测试模式
dip -v                     # 详细模式
dip -p ppp                 # 使用PPP协议
dip -i                     # 交互模式
dip 配置文件.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

常用选项

选项 描述
-t 测试模式,显示命令但不执行
-v 详细模式,显示详细信息
-i 交互模式,进入dip命令行界面
-k 保持运行,即使连接断开
-a 自动模式,读取配置文件自动拨号
-p proto 指定协议:ppp、slip、cslip、adaptive
-m mtu 设置MTU(最大传输单元)大小
-c device 指定串行设备(如/dev/ttyS0)
-b speed 设置串行端口速率(如115200)
-l lockfile 指定锁文件位置
-h 显示帮助信息

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 退出脚本
# 注释符号

实际示例

示例1:基本拨号脚本

创建一个简单的拨号脚本:

# 文件名: 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

示例2:完整的PPP拨号脚本

创建完整的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

示例3:交互模式使用

在交互模式下使用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>?

示例4:自动重连脚本

创建自动检测和重连的脚本:

#!/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

示例5:使用dip与pppd配合

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

示例6:故障排查和调试

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:

调试步骤:

  1. 使用详细模式:dip -v script.dip
  2. 测试模式:dip -t script.dip(不执行)
  3. 添加调试输出:在脚本中使用print命令
  4. 检查硬件:确认调制解调器和串行线正常工作
  5. 查看日志:tail -f /var/log/syslog
  6. 手动测试:使用minicomcu测试调制解调器
  7. 简化脚本:创建最小测试脚本定位问题
  8. 检查权限:确保对/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