Sử dụng hai địa chỉ IP khác nhau cho mỗi máy chủ trong SSH


23

Tôi có một máy chủ, được đặt tên gamma, liên tục hoạt động. Đôi khi tôi kết nối với nó từ ở nhà, trong trường hợp đó tôi sử dụng địa chỉ IP công cộng 55.22.33.99. Đôi khi, tôi kết nối với nó khi tôi đang làm việc và thay vì trả lại các gói của mình xung quanh một cách không cần thiết, tôi kết nối qua địa chỉ IP cục bộ , 192.168.1.100.

Hiện tại, tôi đã chia chúng thành hai mục khác nhau trong ~/.ssh/conf

Host gamma-local
        HostName 192.168.1.100
        Port 22
        User andreas

Host gamma-remote
        HostName 55.22.33.99
        Port 12345
        User andreas

Vì vậy, nếu tôi đang làm việc, tất cả những gì tôi phải gõ là ssh gamma-localvà tôi đang ở; nếu tôi ở nhà (hoặc bất cứ nơi nào khác trên thế giới), tôi sẽ chạy ssh gamma-remote.

Khi kết nối với máy chủ, tôi không muốn phải nhập một tên khác tùy thuộc vào vị trí của tôi, tôi muốn phần đó được thực hiện tự động; chẳng hạn, trong một số trường hợp, tôi có các tập lệnh tự động kết nối những người không biết tôi đang ở đâu.

một câu hỏi giải quyết vấn đề này bằng cách sử dụng tập lệnh Bash để "thử" kết nối với cục bộ trước và nếu nó không kết nối, hãy thử kết nối với địa chỉ IP từ xa. Điều này là tốt, nhưng (1) có vẻ không hiệu quả (đặc biệt là đôi khi bạn phải "chờ" kết nối hết thời gian vì chúng không luôn gửi lại lỗi ngay lập tức) và (2) yêu cầu Bash và xử lý tập lệnh.

Có một cách khác để đạt được điều này mà không dựa vào việc sử dụng các tập lệnh Bash, cũng không phải "thử nghiệm" để xem kết nối có hoạt động trước không?


Những gì tôi đang cố gắng tìm hiểu là liệu người ta có thể mân mê /etc/hostshoặc tập tin cấu hình SSH để đạt được điều này không? Hoặc có lẽ một số cách "phát hiện" mạng LAN nào bạn đang kết nối?
IQAndreas

Bạn có một bộ máy chủ tên riêng được sử dụng bởi mạng văn phòng của bạn không?
Sree

@Sree Ah, tôi thấy bạn đang hướng tới đâu; tài giỏi! Hiện tại chúng tôi không chạy máy chủ tên, nhưng tôi chắc chắn có thể chuyển đổi một trong các máy thành một.
IQAndreas

@Sree Hãy giải thích và thêm vào đó như một câu trả lời bắt đầu bằng dòng "Nếu bạn có một máy chủ tên trên mạng văn phòng của bạn ..."
IQAndreas 22/12/14

Đã làm điều đó. Hãy thoải mái lên / xuống bình chọn :)
Sree

Câu trả lời:


28

Nếu bạn có cách nhận biết bạn đang sử dụng mạng nào thì bạn có thể sử dụng Matchtừ khóa ~/.ssh/configđể làm những gì bạn muốn. Điều này đòi hỏi OpenSSH ≥6,5.

Tôi sử dụng một cái gì đó tương tự như

Match originalhost gamma exec "[ x$(/sbin/iwgetid --scheme) != xMyHomeESSID ]"
  HostName 192.168.1.100
  Port 22

Host gamma
  User andreas
  Port 12345
  HostName 55.22.33.99

Vì vậy, tôi đang sử dụng định danh của mạng wifi đã sử dụng để quyết định xem tôi có ở nhà vì mục đích kết nối SSH hay không, nhưng kiểm tra địa chỉ IP được gán cho máy tính của bạn hoặc bất kỳ thứ gì khác có thể sử dụng cả hai mạng cũng có thể được sử dụng .


+1 sử dụng thông minh Match, cảm ơn! Nó có thể là một ý tưởng tốt để bọc phát hiện thành một tập lệnh thoát với trạng thái thoát 0 hoặc khác không, vì điều đó sẽ làm cho nó có thể tái sử dụng.
peterph

@peterph chắc chắn nó có thể được trừu tượng hóa thành một tập lệnh bên ngoài, nhưng tôi chỉ cần ở một nơi cho đến bây giờ, vì vậy quy tắc ba vẫn chưa được thực hiện.
Michał Politowski

Điều gì sẽ xảy ra nếu bạn đang ở nơi làm việc, nhưng bạn thực sự muốn kết nối với một số máy khác? Câu lệnh exec sẽ không khớp vì bạn không ở trên WiFi với HomeESSID và do đó đặt tên máy chủ thành 192.168.1.100?
đi

@gone Tôi không hiểu câu hỏi. Trận đấu cũng là trên máy chủ mục tiêu.
Michał Politowski

1
@typelogic Không dễ, theo như tôi biết. Bạn có thể thử sử dụng ProxyCommand nc $address ssh, nhưng sau đó, ví dụ. tất cả các thiết bị có cùng khóa máy chủ không? Quảng cáo nếu bạn phải đặt biến môi trường bằng mọi cách, sẽ không dễ dàng hơn nếu chỉ cung cấp địa chỉ để kết nối trực tiếp làm đối số ssh?
Michał Politowski

5

Nếu bạn tình cờ có một máy chủ tên riêng tại nơi làm việc và nếu bạn sử dụng cùng một máy tính xách tay từ văn phòng và nhà, bạn có thể tận dụng điều đó để đạt được điều này:

  1. Sửa đổi nsswitch.conftrong máy của bạn để kiểm tra DNS trước
  2. Tạo một mục DNS gammađể giải quyết 192.168.1.100 trong DNS riêng của bạn tại văn phòng.
  3. Tạo một mục trong tệp / etc / hosts của máy để giải quyết gammathành 55,22.33,99.

Bằng cách này, khi bạn ssh gammatừ văn phòng, nó sẽ phân giải từ DNS văn phòng sang 192.168.1.100 và khi bạn kết nối từ nhà, nó sẽ phân giải thành 55,22.33,99 từ tệp máy chủ của bạn.

PS : Câu trả lời này giả định rằng bạn không muốn gamma có mục nhập DNS công khai. Ngoài ra, nếu bạn đang SSH đến máy chủ của mình từ máy Windows, tôi nghĩ rằng nên có một số vị trí tương đương với tệp nssswitch.conf để ghi đè các mục nhập tệp máy chủ.


Có - đó là tập tin máy chủ. Và đây chính xác là cách tôi làm điều đó - khi ở nhà, miền công cộng của tôi phân giải thành ip cục bộ của tôi. Câu trả lời tuyệt vời - đó là điều đầu tiên tôi nghĩ đến. Chà ... hôm nay, khi tôi thiết lập nó vài năm trước, tôi đã phải google rất nhiều để tìm ra giải pháp.
mikeerv

2

Tôi không biết liệu có thể thực hiện việc này hay không ~/.ssh/confignhưng cách tiếp cận khác sẽ là kết nối với cái này hoặc cái kia dựa trên địa chỉ IP bên ngoài của bạn. Vì, có lẽ, khi bạn đang làm việc, IP của bạn sẽ 55.22.33.NNN, bạn có thể chạy một cái gì đó như:

[[ $(wget -qO - http://wtfismyip.com/text) =~ ^'55.22.33.' ]] && 
    ssh 192.168.1.100 ||
    ssh -p 12345 55.22.33.99

Một cách tiếp cận thậm chí đơn giản hơn là sử dụng IP nội bộ của bạn. Tôi không biết hai mạng của bạn được thiết lập như thế nào nhưng nếu dễ dàng xác định xem bạn có đang làm việc hay không thông qua IP của bạn (ví dụ: nếu bạn có một IP cụ thể tại nơi làm việc, chẳng hạn như 192.168.1.12), bạn có thể làm ( thay đổi eth0thành tên thẻ mạng của bạn là gì):

[[ $(ip address show dev eth0 | grep -Po 'inet \K[\d.]+') = '192.168.1.12' ]] && 
    ssh 192.168.1.100 ||
    ssh -p 12345 55.22.33.99

Bất cứ khi nào bạn quyết định sử dụng, bạn có thể thêm nó dưới dạng bí danh vào trình bao của mình (thêm dòng này vào tệp khởi tạo của trình bao, ~/.bashrcnếu bạn đang sử dụng bash):

alias gamma="[[ $(wget -qO - http://wtfismyip.com/text) =~ ^'55.22.33.' ]] && ssh 192.168.1.100 || ssh -p 12345 55.22.33.99

Bạn cũng có thể biến nó thành một tập lệnh nếu bạn muốn các tập lệnh khác có quyền truy cập vào tập lệnh đó (bí danh từ .bashrckhông được đọc khi chạy tập lệnh).


2

Bạn không thể đạt được điều này ~/.ssh/configkhi sử dụng địa chỉ IP làm tên máy chủ. Sự phức tạp thêm được đưa ra bởi thực tế, rằng bạn không chỉ kết nối với các địa chỉ IP khác nhau mà còn các cổng khác nhau, vì điều đó có khá nhiều quy tắc đối với bất kỳ điều chỉnh nào của trình phân giải DNS của bạn.

Tôi đứng chính xác - bạn có thể sử dụng Match originalhost ... exec ...kết hợp trong ~/.ssh/config- xem câu trả lời của @ MichałPolitowski . Tuy nhiên, mặc dù nó sẽ hoạt động hoàn toàn tốt cho OpenSSH, bạn có thể không nhất thiết phải tìm thấy chức năng tương tự trong các máy khách SSH khác.

Bạn có thể giải quyết vấn đề bằng cách sử dụng trình bao bọc đơn giản (có thể là hàm shell hoặc tập lệnh nếu bạn cần sử dụng nó từ nhiều shell khác nhau) để sshkiểm tra xem bạn đang sử dụng mạng nào và sử dụng Hostmục nhập phù hợp . Câu hỏi lớn là, làm thế nào để phát hiện đáng tin cậy bạn đang ở trên mạng nào. Địa chỉ IP cục bộ xuất hiện trong tâm trí, nhưng không đáng tin cậy, vì bạn cũng có thể đang kết nối từ một mạng LAN sử dụng cùng mạng con như mạng công việc của bạn.

Nếu bạn có thể có cùng một cổng cho cả mạng cục bộ và mạng từ xa, bạn có thể chỉnh sửa /etc/resolv.conftùy thuộc vào mạng bạn đang bật - rõ ràng là nó phải được thực hiện tự động (rất có thể là từ tập lệnh hook của máy khách DHCP của bạn). Hoặc - tốt hơn - chạy máy chủ tên cục bộ (ví dụ như dnsmasq) và cung cấp cho nó cấu hình phù hợp. Điều đó vượt ra ngoài phạm vi của câu hỏi này mặc dù.

Một tùy chọn khác - nếu bạn chỉ cần kết nối tương tác - là sử dụng hoàn thành lệnh sẽ quét ~/.ssh/config. Điều đó sẽ giúp bạn tiết kiệm một số thao tác gõ (đặc biệt nếu bạn có đủ Hostcác mục nhập khác nhau ). Một cái gì đó như thế này (để bashkhởi tạo):

# complete session names for ssh
declare -g _ssh_complete_hostlist 2> /dev/null
function _ssh_complete_init () {
    _ssh_complete_hostlist=$( \
        sed -nr '/^\s*Host\s*=/{s/^[^=]+= *//;s/ /\n/g;p}' ~/.ssh/config \
        | sort )
}
_ssh_complete_init

function _ssh_complete () {
    local match=${COMP_WORDS[${COMP_CWORD}]}
    local hosts=
    local default=
    for h in $_ssh_complete_hostlist; do
        if [[ $h =~ ^$match ]]; then
            hosts="$hosts $h"
        fi
    done
    if ! (( ${COMP_CWORD} == ${#COMP_WORDS[@]}-1 )); then
        default=$( compgen -f ${COMP_WORDS[${COMP_CWORD}]} )
    fi
    COMPREPLY=($hosts $default)
}
complete -F _ssh_complete ssh

Hàm đầu tiên tạo một danh sách mà từ đó các máy chủ được hoàn thành (thông thường nó đủ để chạy một lần trong mỗi shell), hàm thứ hai thực hiện hoàn thành thực tế, mặc dù theo cách hơi vụng về - nó chỉ hoàn thành tên máy chủ khi nó mã thông báo cuối cùng trên dòng lệnh.

Tất cả những gì đã nói, cách đúng đắn để tiếp cận vấn đề này là kết nối vào mạng làm việc thông qua VPN và do đó có thể truy cập địa chỉ IP công việc cục bộ như thể bạn đang ở trong văn phòng. Bạn có thể sau đó cứng-wire địa chỉ vào bất cứ điều gì bất cứ lớp bạn thích: ~/.ssh/config, /etc/resolv.confhoặc (IMHO tốt nhất tùy chọn) máy chủ tên văn phòng.


Các cổng không được đặt trong đá. Tôi chắc chắn có thể thay đổi cổng SSH cục bộ gammađể khớp với cổng từ xa nếu điều đó giúp mọi việc dễ dàng hơn.
IQAndreas

2

Vài năm trước, tôi đã viết một chương trình cho một mục đích tương tự. Nó có thể đáp ứng nhu cầu của bạn. Với chương trình đó, cấu hình ssh có thể trông như thế này:

Host gamma
    ProxyCommand ssh-multipath-proxy 192.168.1.100:22 55.22.33.99:12345
    User andreas

1

Một giải pháp khác là sử dụng hai tệp cấu hình khác nhau cho SSH. Bạn có thể xem xét điều này hơi kém thanh lịch so với việc có mọi thứ trong một tệp cấu hình, nhưng nó dễ bảo trì hơn.

Bạn chọn tập tin cấu hình bạn muốn sử dụng -F <configfile>.


Cảm ơn. Tôi thích -Ftùy chọn này.
typelogic

0

Câu trả lời một phần:

Nhiều câu trả lời ở trên bắt đầu bằng "nếu bạn có thể phát hiện ra mạng nào bạn đang truy cập". Đối với điều này, tôi sử dụng một tập lệnh chạy khi các giao diện được kết nối để bắt đầu nhiều thứ khác nhau (VPN, thường) khi tôi kết nối với một trong các mạng thông thường của mình. Kỹ thuật này là sử dụng ARP để lấy địa chỉ MAC của cổng:

function identifyConnection {
    gatewayIP=$(route -n | grep -e '^0\.0\.0\.0' | tr -s ' ' | cut -d ' ' -f 2)

    if [[ ! -z "$gatewayIP" ]]
    then
        # Identify the gateway by its MAC (uniqueness...)
        log "Gateway IP address=$gatewayIP"
        log "Obtaining corresponding gateway MAC address"
        gatewayData=($(arp -n $gatewayIP | grep -e $gatewayIP | tr -s ' '))
        if [[ "${gatewayData[1]}" == "(incomplete)" ]]
        then
            log "Status of gateway $gatewayIP "incomplete""
            echo ""
        elif [[ "${gatewayData[2]}" == "--" ]]
        then 
            log "No MAC address found for $gatewayIP"
            echo ""
        else
            log "Gateway MAC address=[${gatewayData[2]}]"
            echo "${gatewayData[2]}"
        fi
    fi
}

Và sau đó tôi có một bảng tra cứu để liên kết mạng với cổng MAC. Tất nhiên, bảng đó có thể chứa một số MAC cho cùng một mạng (trường hợp điển hình là các điểm truy cập Wifi khác nhau trên một trang web công ty lớn). Một bảng tra cứu khác được sử dụng để xác định tập lệnh chạy cho mạng đó.

Trong trường hợp của tôi, tập lệnh được chạy bằng thông báo trên màn hình Plasma, vì vậy mọi thứ đều ở trong vùng người dùng.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.