2011-12-16 15 views
5

Tôi có môi trường sau đây: 2 host, mỗi với 2 giao diện Ethernet kết nối với eachother (như trên sơ đồ dưới đây):thế nào để tránh định tuyến thông qua đống địa phương trong Linux

+---------+    +---------+      
|  (1)+---------------+(2)  |  
| host1 |    | host2 | 
|   |    |   | 
|  (3)+---------------+(4)  | 
+---------+    +---------+ 

Tôi muốn viết client/công cụ socket máy chủ sẽ mở cả ổ cắm máy khách và máy chủ trên host1. Tôi muốn khách hàng gửi gói TCP thông qua giao diện (1) và máy chủ để nghe trên giao diện (3), gói đó sẽ đi qua host2.

Thông thường, ngăn xếp Linux sẽ định tuyến các gói này thông qua ngăn xếp TCP/IP cục bộ mà không gửi chúng đến host2.

Tôi đã cố gắng sử dụng SO_BINDTODEVICE tùy chọn cho cả máy chủ và máy khách và có vẻ như máy chủ thực sự được liên kết với giao diện (3) và không nghe lưu lượng cục bộ. Tôi đã kiểm tra client đó từ host1 không thể chấp nhận được trong khi client từ host2 thực hiện.

Thật không may là các gói tin của khách hàng không được gửi đi (thậm chí tcpdump trên giao diện (1) không thấy các gói) thông qua giao diện (1) đến giao diện (2). Định tuyến của khóa học là chính xác (tôi có thể ping (2) từ (1), (4) từ (1), (4) từ (3) vv).

Câu hỏi của tôi là liệu điều này có thể được triển khai mà không sử dụng ngăn xếp TCP/IP tùy chỉnh không?

Có lẽ tôi nên cố gắng thay đổi địa chỉ IP đích (từ máy khách) thành mạng bên ngoài (và sau đó sẽ được gửi bằng cổng mặc định từ giao diện (1) - giao diện (2)) và sau đó đăng lại thay đổi lại bản gốc? Giải pháp đó có thể hoạt động không?

Tôi đang viết đơn đăng ký của mình bằng C dưới Debian.

Thêm một số chi tiết và làm rõ:

  1. tất nhiên cả cặp (1) - (2) và (3) - (4) là mạng con khác nhau
  2. những gì tôi muốn đạt được là (1) -> (2) -> (4) -> (3)
  3. host2 là hộp đen vì vậy tôi không thể cài đặt ở đó bất kỳ gói chuyển tiếp nào (sẽ mở ổ cắm nghe trên giao diện (2) và chuyển tiếp đến (3) đến (4)) - đây chính là điều tôi muốn tránh

T vấn đề chính của ông dường như là giao hàng địa phương. Khi tôi mở socket trên host1 và muốn kết nối với socket, đó là lắng nghe trên địa chỉ khác của cùng một máy chủ hạt nhân chỉ sử dụng stack địa phương để cung cấp các gói tin. Xem sơ đồ netfilter dưới đây:

--->[1]--->[ROUTE]--->[3]--->[4]---> 
      |   ^
      |   | 
      |   [ROUTE] 
      v   | 
      [2]   [5] 
      |   ^
      |   | 
      v   | 

gói đang trải qua [5] NF_IP_LOCAL_OUT và [2] NF_IP_LOCAL_IN trong khi tôi muốn buộc họ phải đi qua [4].

+0

Chỉ cần để hiểu bạn muốn con đường thông điệp của bạn là (1) -> (2) -> (4) -> (3)? –

+0

Bạn chắc chắn không cần một ngăn xếp TCP tùy chỉnh cho việc này. Bạn không chắc chắn nếu đó là cách tốt nhất, nhưng bạn có thể thực hiện một số dịch địa chỉ mạng trên host2 sẽ ánh xạ một số địa chỉ IP duy nhất tới địa chỉ giao diện (3) và đảm bảo các gói tin (3) từ host2 được định tuyến thông qua (4)). Host1 sau đó sẽ kết nối với địa chỉ IP duy nhất đó. – NPE

+0

Nếu một ổ cắm kết nối từ (1) đến (2) trên một máy khác và ổ cắm khác kết nối (4) đến (3) trên máy đầu tiên, tại sao ngăn xếp TCP Linux bỏ qua việc gửi gói tin qua mạng? Làm thế nào có thể ngăn xếp TCP _possibly_ biết về cấu trúc liên kết bất thường này và làm thế nào nó có thể _possibly_ biết ý định của bạn? – Damon

Trả lời

-1

Bạn có thể gán các mạng con khác nhau cho (1) - (2) và (3) - (4) cặp và host2 chuyển tiếp các gói từ (2) đến (3). Máy khách trên host1 sẽ kết nối đến địa chỉ của (2), vì vậy ngăn xếp mạng cục bộ sẽ không biết rằng máy chủ đích thực sự đang chạy cục bộ.

+0

Trên thực tế có các mạng con khác nhau giữa (1) - (2) và (3) - (4). Để sử dụng giải pháp này, tôi sẽ cần một số giao nhận trên host2, sẽ lắng nghe các gói tin từ giao diện (2) và gửi tới giao diện (3) - thông qua giao diện (4). Host2 là hộp đen, vì vậy tôi không thể cài đặt bất kỳ phần mềm bổ sung nào ở đó. Dù sao khách hàng từ host1 sẽ được kết nối với máy chủ lắng nghe trên giao diện (2), chính xác những gì tôi muốn tránh. – codewarrior

+0

Bạn cần * một cái gì đó * để phản ánh các gói được gửi từ giao diện (1) đến giao diện (3) - một máy tính hoạt động như một bộ định tuyến, một thiết lập junkbox linksys với nat, bất cứ điều gì. Sáng tạo. –

+0

Vấn đề là gửi gói tin ra khỏi host1 một lần nữa.Ngay cả khi định tuyến được đặt để gửi tất cả các gói thông qua cổng mặc định được đặt thành giao diện (2) khiến các gói gửi tới giao diện thứ hai của cùng một thiết bị không được định tuyến bằng cổng mặc định. Nếu tôi ràng buộc client socket explicity để can thiệp (1) các gói bị bỏ bởi kernel (thậm chí tcpdump chạy trên giao diện (1) không thấy các gói). Vì vậy, vấn đề dường như không phải là với định tuyến chính nó, mà là với giao hàng stack địa phương. – codewarrior

4

chưa được kiểm tra (nên làm việc, nhưng tôi có thể có một cái gì đó bỏ lỡ):

Linux có một số bảng định tuyến.Bảng local chứa một số tuyến đường mà hạt nhân tự động thêm cho mọi địa chỉ IP được thêm vào máy chủ lưu trữ. Bạn có thể xem chúng với ip route show table local. Các tuyến đường được gắn nhãn là địa phương cho biết các tuyến đường địa phương đi qua giao diện vòng lặp. Bạn có thể xóa con đường đó và thêm một bình thường unicast lộ trình để thay thế nó:

ip route del table local <ip> dev <NIC> 
ip route add table local <ip> dev <NIC> 
ip route flush cache 

Lúc này cái hộp 1 của bạn sẽ cố gắng gửi IP datagram đến địa chỉ IP như thể nó là một địa chỉ từ xa, ví dụ như: nó sẽ sử dụng ARP. Vì vậy, hộp thứ 2 bạn sẽ phải hoặc là trả lời các yêu cầu ARP nếu nó được hoạt động như một router hoặc đang làm proxy ARP, hoặc bạn sẽ có thêm một hiệp hội để bộ nhớ cache ARP:

arp -s <ip> <MAC> 

Sau đó, có thể bạn sẽ phải vô hiệu hóa rp_filter trên giao diện:

echo 0 > /proc/sys/net/ipv4/conf/<NIC>/rp_filter 

Them một lần nữa, nếu điều này không làm việc, bạn có thể có thể thiết lập một cái gì đó với L2 NAT, sử dụng ebtables.

+0

Bạn có nghĩa là 'unicast' thay vì' local' trên dòng 'ip' thứ hai không? –

+0

@NikolaiNFetissov: ** local ** dành cho tên bảng. Tôi đã không thực sự xác định loại tuyến đường trong một trong hai lệnh, cho một trong những đầu tiên IP có lẽ sẽ là đủ để chọn một tuyến đường duy nhất để xóa, cho một thứ hai ** unicast ** là loại tuyến đường mặc định. – ninjalj

+0

@NikolaiNFetissov: và có, tôi đã kiểm tra phần đó, gói được xem trên 'tcpdump -ni eth0'. Tôi đã không kiểm tra toàn bộ thiết lập, tôi quá lười biếng cho điều đó. Dù sao, OP có lẽ không cần phần 'ARP' cũng không phải phần' rp_filter'. – ninjalj

2

Đối với một nhiệm vụ rất giống tôi đang sử dụng kịch bản như:

ip rule add from all lookup local # add one more local table lookup rule with high pref 
ip rule del pref 0 # delete default local table lookup rule 
ip rout add ${ip3} via ${ip2} src ${ip1} table 100 # add correct route to some table 
ip rule add from all lookup 100 pref 1000 # add rule to lookup new table before local table