2009-07-12 76 views
5

Tôi đang viết một ứng dụng máy chủ tcp đơn giản bằng cách sử dụng ổ cắm. Theo như tôi biết tôi có thể có được địa chỉ ip của khách hàng và cổng sau khi gọi điện thoại chấp nhận().Từ chối kết nối từ máy chủ

Bây giờ, giả sử tôi có danh sách cấm và tôi muốn cấm một số địa chỉ ip từ máy chủ của mình. Có cách nào tốt hơn chấp nhận kết nối và sau đó thả nó?

Có cách nào để nhận ip và cổng của khách hàng trước khi chấp nhận kết nối không? Nếu chúng ta chấp nhận() tại sao chúng ta không có thứ gì đó giống như từ chối()? Có cách nào để từ chối kết nối hoặc chỉ đơn giản là bỏ qua nỗ lực kết nối từ máy chủ lưu trữ?

+0

bạn có thể thêm thẻ cho ngôn ngữ bạn sử dụng không? Tôi không phải là một chuyên gia ổ cắm, nhưng tôi có một số kinh nghiệm từ Actionscript và C# /. NET – BerggreenDK

+2

Và hệ điều hành cũng ... Windows vs Unix có thể tạo sự khác biệt lớn ở đây. Tôi không nghĩ rằng có một giải pháp di động, nhưng tôi có thể sai. –

Trả lời

13

Việc thực hiện TCP thường hoàn TCP 3-way handshake trước khi quá trình sử dụng thậm chí còn có quyền truy cập vào các kết nối, và hàm accept() chỉ nhận được kết nối tiếp theo ngoài hàng đợi. Vì vậy, đã quá muộn để giả vờ rằng máy chủ bị hỏng. Điều này làm việc theo cùng một cách cho dữ liệu TCP thông thường; việc triển khai TCP không chờ cho ứng dụng thực sự là recv() dữ liệu trước khi gửi TCP ACK. Điều này giữ cho phía bên kia không cần thiết truyền lại các gói tin đã nhận được một cách chính xác, và cho phép thông lượng vẫn còn cao, ngay cả khi ứng dụng bị sa lầy với những thứ khác. Trong trường hợp các kết nối mới (các gói SYN), điều này cũng cho phép hạt nhân tự bảo vệ (và ứng dụng) khỏi các cuộc tấn công SYN flood.

Mặc dù không di động, nhiều nền tảng cung cấp một số loại khả năng tường lửa cho phép lọc kết nối đến dựa trên địa chỉ IP/cổng. Tuy nhiên, nó thường được cấu hình trên toàn hệ thống chứ không phải bởi một ứng dụng riêng lẻ.

+0

Vì vậy, nếu tôi nghe trên một cổng kết nối sẽ được thiết lập trong nền bất kể tôi muốn hay không? – Calmarius

+1

Gọi nghe() cho hệ điều hành biết rằng bạn muốn bất kỳ kết nối nào có thể được thiết lập thành công trên cổng của bạn. Vì vậy, trừ khi bạn lọc gói ở mức thấp hơn (quy tắc tường lửa), nó sẽ phản hồi mọi yêu cầu kết nối đến cổng này. Nếu bạn quyết định rằng bạn không muốn một kết nối cụ thể, bạn luôn có thể đóng() nó, đó là những gì một số câu trả lời khác ở đây sẽ làm. – mark4o

4

On cửa sổ: nhìn vào WSAAccept, có thể đó là những gì bạn cần:

SOCKET WSAAccept(
    __in  SOCKET s, 
    __out struct sockaddr *addr, 
    __inout LPINT addrlen, 
    __in  LPCONDITIONPROC lpfnCondition, 
    __in  DWORD dwCallbackData 
); 

lpfnCondition - địa chỉ của một tùy chọn, ứng dụng quy định chức năng tình trạng đó sẽ làm cho một chấp nhận/từ chối quyết định dựa trên thông tin người gọi được truyền vào dưới dạng tham số, và tùy chọn tạo hoặc tham gia nhóm ổ cắm bằng cách gán một giá trị thích hợp cho tham số kết quả g của hàm này. Nếu tham số này là NULL, thì không có hàm điều kiện nào được gọi.

Để xem linux xem giải pháp: GNU Common C++ - Lớp TCPSocket, nó có phương thức onAccept() và reject().

virtual bool TCPSocket::onAccept (  const InetHostAddress &  ia, 
     tpport_t port 
    ) [inline, protected, virtual] 

Phương thức gọi trong lớp TCPSocket có nguồn gốc khi yêu cầu kết nối được chấp nhận.

Máy chủ có thể triển khai các quy tắc cụ thể của giao thức để loại trừ socket từ xa không được chấp nhận bằng cách trả về false. Phương pháp Peek cũng có thể được sử dụng cho mục đích này.


Tuy nhiên, bạn có thể chỉ cần ổ cắm đóng cửa sau khi chấp nhận nếu điều kiện tiên quyết là sai :)

+0

Nếu không có giải pháp nào khác, tôi sẽ chấp nhận và đóng ổ cắm ngay lập tức như mở cửa để hỏi bạn là ai và đóng cửa nếu bạn bị cấm ... Nhưng tôi không muốn mở cánh cửa đó chút nào. Tôi muốn làm cho người dùng bị cấm nghĩ rằng máy chủ chỉ đơn giản là xuống. – Calmarius

+0

Những gì bạn muốn là thanh lịch hơn, tuy nhiên trong phát triển chúng ta cần sự cân bằng giữa các tính năng biết ơn và thời gian/tiền chi cho nó. Giống như trong XP nói - làm theo cách đơn giản nhất, sau đó bạn có thể đến và cấu trúc lại nó. –

1

TCP Wrapper đã trở nên rất phổ biến trên các nền tảng giống UNIX. Có, kết nối chỉ được kiểm tra sauaccept; tuy nhiên, nếu bạn đang làm điều này anyways, bạn cũng có thể sử dụng cùng một cấu hình mà mọi người khác sử dụng.

Về cơ bản, chương trình của bạn là một trong hai chạy với tcpd hoặc sửa đổi để sử dụng libwrap trực tiếp, như vậy:

#include <tcpd.h> 
connfd = accept(listenfd, (struct sockaddr *)&addr, &addrlen); 
if (!hosts_ctl("my_program", STRING_UNKNOWN, inet_ntoa(addr.sin_addr), STRING_UNKNOWN)) { 
    fprintf(stderr, "Client %s connection disallowed\n", inet_ntoa(addr.sin_addr)); 
    close(connfd); 
} 

Sau đó, bạn cấu hình /etc/hosts.allow/etc/hosts.deny theo ham muốn của bạn, ví dụ

 
# /etc/hosts.allow 
my_program: 127.0.0.1 10. 192.168. 

# /etc/hosts.deny 
my_program: ALL 

Điều này sẽ gây my_program để từ chối tất cả các cố gắng kết nối từ địa chỉ không địa phương, nhưng có thể được thay đổi mà không cần chạm my_program ở tất cả.

-1

khái niệm không chấp nhận kết nối dựa trên địa chỉ IP sẽ không hoạt động nếu bạn đang băm NAT.

Các vấn đề liên quan