본문 바로가기
Shell Script/Routing Check

(Shell Script) 리눅스 라우팅 정보 추가를 위한 Bash 스크립트

by 미니몬 2023. 10. 12.

목차

    728x90
    반응형

    Summary

    안녕하세요,

    리눅스에서 사용되는 라우팅 파일에 원하는 라우팅 정보를 쉽게 추가할 수 있는 Bash 스크립트를 소개하려고 합니다.

    해당 스크립트를 사용하면 라우팅 테이블 정보를 효과적으로 관리하고, 실수 없이 추가 및  수정할 수 있습니다.

    각 코드의 섹션별로 어떤 기능을 하는지 설명해 드리겠습니다.


    1) 스크립트 개요

    이 스크립트는 다음과 같은 기능을 제공합니다.

    • 라우팅 파일의 위치 및 이름을 자동으로 파악
    • IP 주소, 넷마스크, 게이트웨이의 유효성 검사
    • 라우팅 정보의 순서를 지정하거나 자동으로 추가
    • 중복된 라우팅 정보의 확인 및 경고

     

    스크립트는 아래와 같은 주요 기능을 포함합니다.

    • 유효성 검사:
      스크립트는 입력된 IP 주소, 넷마스크, 게이트웨이의 유효성을 검사하여, 잘못된 정보가 입력되지 않도록 합니다.
    • 라우팅 정보 순서 지정: 
      사용자는 추가할 라우팅 정보의 순서를 직접 지정할 수 있습니다. 
      순서를 지정하지 않을 경우, 자동으로 마지막 순서에 추가합니다.
    • 중복 검사: 
      이미 존재하는 라우팅 정보가 입력될 경우 추가되지 않습니다.
      스크립트는 해당 정보를 경고하고 중복된 정보를 출력합니다.
    • 라우팅 정보 추가: 
      사용자의 확인을 받은 후, 스크립트는 라우팅 파일에 새로운 라우팅 정보를 추가합니다.

    2) 전체 코드 및 사용법

    코드 펼처보기 ↓

    더보기
    #!/bin/bash
    
    usage() {
        echo "    Error: No input value provided."
        echo "    Usage: $0 <Device_Name>"
        echo "       Ex: $0 bond0"
        exit 1
    }
    
    if [ -z "$1" ]; then
        usage
    fi
    
    ROUTE_PATH="/etc/sysconfig/network-scripts"
    INTERFACE_NAME="$1"
    ROUTE_FILE="route-$INTERFACE_NAME"
    ROUTING_FILE="$ROUTE_PATH/$ROUTE_FILE"
    
    if [ ! -e "$ROUTING_FILE" ]; then
        echo "Error: $ROUTING_FILE not found."
        exit 1
    fi
    
    validate_ip_address() {
        local ip_address="$1"
        local regex="^(25[0-5]|2[0-4][0-9]|[0-1]?[0-9]?[0-9])(\.(25[0-5]|2[0-4][0-9]|[0-1]?[0-9]?[0-9])){3}$"
    
        if [[ $ip_address =~ $regex ]]; then
            return 0
        else
            return 1
        fi
    }
    
    get_add_info() {
        last_seq_num=$(grep -oP "^ADDRESS\K[0-9]+" "$ROUTING_FILE" | sort -rn | head -n1)
        
        echo "Current Last Sequence is [$last_seq_num]"
        while true; do
            read -p "NEW SEQUENCE NUMBER (Leave empty for adding to the end): " SEQ_NUM
            if [[ $SEQ_NUM -gt $((last_seq_num + 1)) ]]; then
                echo -e "\nEnter Less than $((last_seq_num + 1)) "
            elif [[ -z "$SEQ_NUM" ]]; then
                last_seq_num=$((last_seq_num + 1))
                break
            elif [[ "$SEQ_NUM" =~ ^[0-9]+$ ]]; then
                last_seq_num=""
                break
            else
                echo "Please enter a valid number or leave it empty."
            fi
        done
    
        while true; do
            read -p "NEW ADDRESS : " NEW_ADDRESS
            if validate_ip_address "$NEW_ADDRESS"; then
                break
            else
                echo "Please enter a valid IP address (0.0.0.0 ~ 255.255.255.255)."
            fi
        done
    
        while true; do
            read -p "NEW NETMASK : " NEW_NETMASK
            if validate_ip_address "$NEW_NETMASK"; then
                break
            else
                echo "Please enter a valid IP address (0.0.0.0 ~ 255.255.255.255)."
            fi
        done
    
        while true; do
            read -p "NEW GATEWAY : " NEW_GATEWAY
            if validate_ip_address "$NEW_GATEWAY"; then
                break
            else
                echo "Please enter a valid IP address (0.0.0.0 ~ 255.255.255.255)."
            fi
        done
    
        echo "========================="
        if [[ -z $last_seq_num ]]; then
            echo -e "ADDRESS$SEQ_NUM = $NEW_ADDRESS \nNETMASK$SEQ_NUM = $NEW_NETMASK \nGATEWAY$SEQ_NUM = $NEW_GATEWAY"
        else
            echo -e "ADDRESS$last_seq_num = $NEW_ADDRESS \nNETMASK$last_seq_num = $NEW_NETMASK \nGATEWAY$last_seq_num = $NEW_GATEWAY"
        fi
        echo "========================="
    
        read -p "Are you going to add this? [y/n]: " confirm
    
        while true; do
            case $confirm in
                "y")
                    echo ""
                    break
                    ;;
                "n")
                    echo -e "\nCancel the add.\n"
                    exit 1
                    ;;
                *)
                    read -p "Please enter 'y' or 'n' [y/n]: " confirm
                    ;;
            esac
        done
    }
    
    add_new_route() {
        if grep -qw "$NEW_ADDRESS" $ROUTING_FILE; then
            echo "[$NEW_ADDRESS] is already exists in $ROUTING_FILE"
            tmp=$(grep $NEW_ADDRESS $ROUTING_FILE | awk -F= '{print $1}')
            tmp_seq=${tmp#ADDRESS}  # Extract sequence number with more than one digit
            echo "`cat $ROUTING_FILE | egrep -w "ADDRESS$tmp_seq|NETMASK$tmp_seq|GATEWAY$tmp_seq"`"
            exit 1
        fi
    
        cp $ROUTING_FILE $ROUTING_FILE.bk
    
        local TEMP_FILE=$(mktemp)
    
        if [[ -z "$SEQ_NUM" ]]; then
            SEQ_NUM=$(grep -oP "^ADDRESS\K[0-9]+" "$ROUTING_FILE" | sort -rn | head -n1)
            ((SEQ_NUM++))
            echo "" >> "$ROUTING_FILE"
            echo "ADDRESS$SEQ_NUM=$NEW_ADDRESS" >> "$ROUTING_FILE"
            echo "NETMASK$SEQ_NUM=$NEW_NETMASK" >> "$ROUTING_FILE"
            echo "GATEWAY$SEQ_NUM=$NEW_GATEWAY" >> "$ROUTING_FILE"
            
            if [ $? -eq 0 ]; then
                echo "ROUTE ADD SUCCESS."
            else
                echo "ADDRESS$SEQ_NUM=$NEW_ADDRESS"
                echo "NETMASK$SEQ_NUM=$NEW_NETMASK"
                echo "GATEWAY$SEQ_NUM=$NEW_GATEWAY"
                echo "Invalid Error"
            fi
            
        else
            # Rearrange sequence numbers
            awk -v seq=$SEQ_NUM -v addr=$NEW_ADDRESS -v mask=$NEW_NETMASK -v gw=$NEW_GATEWAY 'BEGIN {FS=OFS="="; inserted=0}
                /^ADDRESS[0-9]+/ {
                    split($1, a, "ADDRESS");
                    num = a[2] + 0;  # Convert to number
                    if (num == seq && !inserted) {
                        print "ADDRESS" seq "=" addr;
                        print "NETMASK" seq "=" mask;
                        print "GATEWAY" seq "=" gw;
                        print "";
                        inserted=1;
                        num++;
                    } else if (num >= seq) {
                        num++;
                    }
                    print "ADDRESS" num "=" $2;
                    next;
                }
                /^NETMASK[0-9]+/ {
                    split($1, a, "NETMASK");
                    num = a[2] + 0;  # Convert to number
                    if (num >= seq) {
                        num++;
                    }
                    print "NETMASK" num "=" $2;
                    next;
                }
                /^GATEWAY[0-9]+/ {
                    split($1, a, "GATEWAY");
                    num = a[2] + 0;  # Convert to number
                    if (num >= seq) {
                        num++;
                    }
                    print "GATEWAY" num "=" $2;
                    next;
                }
                {print $0}
            ' $ROUTING_FILE > $TEMP_FILE
    
            mv $TEMP_FILE $ROUTING_FILE
            if [ $? -eq 0 ]; then
                echo "ROUTE ADD SUCCESS."
            else
                echo "ADDRESS$SEQ_NUM=$NEW_ADDRESS"
                echo "NETMASK$SEQ_NUM=$NEW_NETMASK"
                echo "GATEWAY$SEQ_NUM=$NEW_GATEWAY"
                echo "Invalid Error"
            fi
        fi
    }
    
    get_add_info
    
    add_new_route
    
    exit 0

     

     

    사용법 펼처보기 ↓

    더보기
    ./script_name.sh <Device_Name>
    또는
    sh script_name.sh <Device_Name>

     

    예시:

    # ./script_name.sh bond0
    Current Last Sequence is [3]
    NEW SEQUENCE NUMBER (Leave empty for adding to the end):
    NEW ADDRESS : 50.50.50.0
    NEW NETMASK : 255.255.255.0
    NEW GATEWAY : 192.168.227.1
    =========================
    ADDRESS4 = 50.50.50.0 
    NETMASK4 = 255.255.255.0 
    GATEWAY4 = 192.168.227.1
    =========================
    Are you going to add this? [y/n]: y

    ROUTE ADD SUCCESS.

     

     

    수정전 수정후
    # cat route-bond0
    #des1
    ADDRESS0=10.10.10.128
    NETMASK0=255.255.255.128
    GATEWAY0=192.168.227.1

    ADDRESS1=20.20.20.64
    NETMASK1=255.255.255.192
    GATEWAY1=192.168.227.1

    ADDRESS2=30.30.30.32
    NETMASK2=255.255.255.224
    GATEWAY2=192.168.227.1

    ADDRESS3=40.40.40.16
    NETMASK3=255.255.255.240
    GATEWAY3=192.168.227.1




    # cat route-bond0
    #des1
    ADDRESS0=10.10.10.128
    NETMASK0=255.255.255.128
    GATEWAY0=192.168.227.1

    ADDRESS1=20.20.20.64
    NETMASK1=255.255.255.192
    GATEWAY1=192.168.227.1

    ADDRESS2=30.30.30.32
    NETMASK2=255.255.255.224
    GATEWAY2=192.168.227.1

    ADDRESS3=40.40.40.16
    NETMASK3=255.255.255.240
    GATEWAY3=192.168.227.1

    ADDRESS4=50.50.50.0
    NETMASK4=255.255.255.0
    GATEWAY4=192.168.227.1

     

     

     

    여기서부터는 스크립트의 내용을 각 섹션별로 나누어 설명하고자 합니다.

    만약 사용만 하시려면 위 사용법만 살펴보셔도 무방합니다.

    코드를 좀 더 자세히 이해하고 입맛대로 수정하실 분들을 위해 자세히 설명드릴테니,

    혹여나 잘못된 부분이 있다면 댓글 부탁드려용..ㅎㅎ


    3) 코드설명

     

    1. 스크립트 실행 확인

    • 이 부분은 사용자가 스크립트를 실행할 때 필요한 인자 (Device_Name)를 제공했는지 확인
    • 제공되지 않았다면, usage 함수를 호출하여 사용법을 출력하고 스크립트를 종료
    usage() {
        echo "    Error: No input value provided."
        echo "    Usage: $0 <Device_Name>"
        echo "       Ex: $0 bond0"
        exit 1
    }
    
    if [ -z "$1" ]; then
        usage
    fi

     

     

    2. 라우팅 파일 경로 지정

    • 여기서는 라우팅 파일의 기본 경로와 인터페이스 이름을 설정
    • 사용자가 입력한 인터페이스 이름을 바탕으로 라우팅 파일의 전체 경로를 구성
    ROUTE_PATH="/etc/sysconfig/network-scripts"
    INTERFACE_NAME="$1"
    ROUTE_FILE="route-$INTERFACE_NAME"
    ROUTING_FILE="$ROUTE_PATH/$ROUTE_FILE"

     

     

    3. 입력한 정보의 유효성 검사 - validate_ip_address()

    • 이 함수는 주어진 정보가 유효한 형식인지 확인
    • 유효한 IP 주소 형식 (0.0.0.0 ~ 255.255.255.255)이 아닐 경우, 사용자에게 다시 입력을 요청

     

     

    4. 새로운 라우팅 정보를 파일에 입력 - get_add_info()

    • 라우팅 파일에서 현재까지 사용된 가장 큰 ADDRESS 시퀀스 번호를 탐색
    last_seq_num=$(grep -oP "^ADDRESS\K[0-9]+" "$ROUTING_FILE" | sort -rn | head -n1)

     

    • 사용자에게 새로운 시퀀스 번호를 입력받고, 입력하지 않으면 자동으로 (마지막 시퀀스+1) 번호를 할당
        while true; do
            read -p "NEW SEQUENCE NUMBER (Leave empty for adding to the end): " SEQ_NUM
            if [[ $SEQ_NUM -gt $((last_seq_num + 1)) ]]; then
                echo -e "\nEnter Less than $((last_seq_num + 1)) "
            elif [[ -z "$SEQ_NUM" ]]; then
                last_seq_num=$((last_seq_num + 1))
                break
            elif [[ "$SEQ_NUM" =~ ^[0-9]+$ ]]; then
                last_seq_num=""
                break
            else
                echo "Please enter a valid number or leave it empty."
            fi
        done

     

    • 추가할 IP주소, NETMASK, 게이트웨이 정보를 입력받고, 유효한 주소 형식인지 판단
        while true; do
            read -p "NEW ADDRESS : " NEW_ADDRESS
            if validate_ip_address "$NEW_ADDRESS"; then
                break
            else
                echo "Please enter a valid IP address (0.0.0.0 ~ 255.255.255.255)."
            fi
        done
    
        while true; do
            read -p "NEW NETMASK : " NEW_NETMASK
            if validate_ip_address "$NEW_NETMASK"; then
                break
            else
                echo "Please enter a valid IP address (0.0.0.0 ~ 255.255.255.255)."
            fi
        done
    
        while true; do
            read -p "NEW GATEWAY : " NEW_GATEWAY
            if validate_ip_address "$NEW_GATEWAY"; then
                break
            else
                echo "Please enter a valid IP address (0.0.0.0 ~ 255.255.255.255)."
            fi
        done

     

    • 입력한 정보를 다시 한번 출력하여 확인시키고 해당 정보를 추가할 것인지 확인
        echo "========================="
        if [[ -z $last_seq_num ]]; then
            echo -e "ADDRESS$SEQ_NUM = $NEW_ADDRESS \nNETMASK$SEQ_NUM = $NEW_NETMASK \nGATEWAY$SEQ_NUM = $NEW_GATEWAY"
        else
            echo -e "ADDRESS$last_seq_num = $NEW_ADDRESS \nNETMASK$last_seq_num = $NEW_NETMASK \nGATEWAY$last_seq_num = $NEW_GATEWAY"
        fi
        echo "========================="
    
        read -p "Are you going to add this? [y/n]: " confirm
        
            while true; do
            case $confirm in
                "y")
                    echo ""
                    break
                    ;;
                "n")
                    echo -e "\nCancel the add.\n"
                    exit 1
                    ;;
                *)
                    read -p "Please enter 'y' or 'n' [y/n]: " confirm
                    ;;
            esac
        done

    요약하면 `get_add_info()` 함수는 사용자로부터 새로운 라우팅 정보를 입력받고,

    해당 정보의 유효성을 검사한 후, 사용자의 최종 확인을 받아 정보를 추가할지 취소할지 결정합니다.

     

     

    5. 입력받은 정보를 실제로 파일에 추가 - add_new_route()

    • 라우팅 파일에서 새로운 IP주소(`$NEW_ADDRESS`) 가 이미 존재하는지 확인
    • 만약 존재한다면, 중복된 정보를 출력하고 스크립트 종료
        if grep -qw "$NEW_ADDRESS" $ROUTING_FILE; then
            echo "[$NEW_ADDRESS] is already exists in $ROUTING_FILE"
            tmp=$(grep $NEW_ADDRESS $ROUTING_FILE | awk -F= '{print $1}')
            tmp_seq=${tmp#ADDRESS}  # Extract sequence number with more than one digit
            echo "`cat $ROUTING_FILE | egrep -w "ADDRESS$tmp_seq|NETMASK$tmp_seq|GATEWAY$tmp_seq"`"
            exit 1
        fi

     

    • 현재 라우팅 파일을 백업하여 수정되기 전 파일을 보존
    cp -f $ROUTING_FILE $ROUTING_FILE.bk

     

    • 추가할 라우팅 정보의 순서가 기본값(미입력)인 경우 파일 제일 하단에 추가
        if [[ -z "$SEQ_NUM" ]]; then
            SEQ_NUM=$(grep -oP "^ADDRESS\K[0-9]+" "$ROUTING_FILE" | sort -rn | head -n1)
            ((SEQ_NUM++))
            echo "" >> "$ROUTING_FILE"
            echo "ADDRESS$SEQ_NUM=$NEW_ADDRESS" >> "$ROUTING_FILE"
            echo "NETMASK$SEQ_NUM=$NEW_NETMASK" >> "$ROUTING_FILE"
            echo "GATEWAY$SEQ_NUM=$NEW_GATEWAY" >> "$ROUTING_FILE"
            
            if [ $? -eq 0 ]; then
                echo "ROUTE ADD SUCCESS."
            else
                echo "ADDRESS$SEQ_NUM=$NEW_ADDRESS"
                echo "NETMASK$SEQ_NUM=$NEW_NETMASK"
                echo "GATEWAY$SEQ_NUM=$NEW_GATEWAY"
                echo "Invalid Error"
            fi

    `$SEQ_NUM` 변수가 지정되지 않은 경우 라우팅 파일의 마지막에 새로운 정보를 추가합니다.

     

    • 순서를 지정한경우 해당 위치에 새로운 정보를 입력하고 라우팅 파일의 시퀀스 번호를 재정의
        else
            # Rearrange sequence numbers
            awk -v seq=$SEQ_NUM -v addr=$NEW_ADDRESS -v mask=$NEW_NETMASK -v gw=$NEW_GATEWAY 'BEGIN {FS=OFS="="; inserted=0}
                /^ADDRESS[0-9]+/ {
                    split($1, a, "ADDRESS");
                    num = a[2] + 0;  # Convert to number
                    if (num == seq && !inserted) {
                        print "ADDRESS" seq "=" addr;
                        print "NETMASK" seq "=" mask;
                        print "GATEWAY" seq "=" gw;
                        print "";
                        inserted=1;
                        num++;
                    } else if (num >= seq) {
                        num++;
                    }
                    print "ADDRESS" num "=" $2;
                    next;
                }
                /^NETMASK[0-9]+/ {
                    split($1, a, "NETMASK");
                    num = a[2] + 0;  # Convert to number
                    if (num >= seq) {
                        num++;
                    }
                    print "NETMASK" num "=" $2;
                    next;
                }
                /^GATEWAY[0-9]+/ {
                    split($1, a, "GATEWAY");
                    num = a[2] + 0;  # Convert to number
                    if (num >= seq) {
                        num++;
                    }
                    print "GATEWAY" num "=" $2;
                    next;
                }
                {print $0}
            ' $ROUTING_FILE > $TEMP_FILE
    
            mv $TEMP_FILE $ROUTING_FILE
            if [ $? -eq 0 ]; then
                echo "ROUTE ADD SUCCESS."
            else
                echo "ADDRESS$SEQ_NUM=$NEW_ADDRESS"
                echo "NETMASK$SEQ_NUM=$NEW_NETMASK"
                echo "GATEWAY$SEQ_NUM=$NEW_GATEWAY"
                echo "Invalid Error"
            fi
        fi

    사용자가 원하는 위치에 정보를 추가하고 awk 명령을 통해 시퀀스 번호를 1씩 증가시켜 재정의 합니다.

    이후 `$TEMP_FILE` 에 저장해 두었던 내용을 엎어치면서 성공/실패 메시지를 출력합니다.


    4) 마치며

    오늘은 리눅스에서 라우팅 테이블 관리에 사용되는 라우팅 파일에 원하는 정보를 추가하는 스크립트를 살펴보았습니다.

    이 스크립트를 사용하면, 리눅스의 라우팅 정보를 효과적으로 관리하고 추가할 수 있습니다. 

    특히, 복잡한 네트워크 환경에서 라우팅 정보를 자주 변경해야 하는 경우, 이 스크립트는 큰 도움이 될 것입니다.

     

     

     

    728x90
    반응형