অব্যবহৃত স্থানীয় বন্দরটি খুঁজে পাওয়ার সহজতম উপায় কী?


52

অব্যবহৃত স্থানীয় বন্দরটি খুঁজে পাওয়ার সহজতম উপায় কী?

বর্তমানে আমি এর অনুরূপ কিছু ব্যবহার করছি:

port=$RANDOM
quit=0

while [ "$quit" -ne 1 ]; do
  netstat -a | grep $port >> /dev/null
  if [ $? -gt 0 ]; then
    quit=1
  else
    port=`expr $port + 1`
  fi
done

এটি ভয়াবহভাবে চারিদিক থেকে অনুভব করে, তাই আমি ভাবছিলাম যে বিল্টিনের মতো আরও সাধারণ কোনও পথ নেই যা আমি মিস করেছি।


2
কেন আপনি যে কাজ করতে চান? এটি সহজাতভাবে বর্ণবাদী (এবং অদক্ষ - এবং কমপক্ষে -nনেটস্ট্যাট এবং আরও নির্বাচনী গ্রেপ যোগ করুন)। এটি করার উপায় হ'ল আপনার প্রয়োজন অনুযায়ী যে কোনও মোডে একটি পোর্ট চেষ্টা করা এবং এটি খোলার এবং এটি উপলভ্য না হলে অন্য একটির চেষ্টা করে।
মাদুর

1
@ ম্যাট আমি সোকস ssh -Dসার্ভার হিসাবে স্বয়ংক্রিয়ভাবে একটি খোলা পোর্ট সন্ধান করার চেষ্টা করছি ।
মাইবুদ্দিমাইকেল

উত্তর:


24

যদি আপনার অ্যাপ্লিকেশন এটি সমর্থন করে, আপনি অ্যাপ্লিকেশনটিতে 0 পোর্টটি পাস করার চেষ্টা করতে পারেন। যদি আপনার অ্যাপ্লিকেশনটি কার্নেলের কাছে চলে যায় তবে অনুরোধের সময় বন্দরটি গতিশীলভাবে বরাদ্দ দেওয়া হবে এবং এটি ব্যবহার না করার গ্যারান্টিযুক্ত (সমস্ত বন্দর ইতিমধ্যে ব্যবহারের ক্ষেত্রে বরাদ্দ ব্যর্থ হবে)।

অন্যথায়, আপনি নিজে এটি করতে পারেন। আপনার উত্তরের স্ক্রিপ্টটিতে একটি রেসের শর্ত রয়েছে, এটি এড়ানোর একমাত্র উপায় এটি খোলার চেষ্টা করে এটি খোলার কিনা তা পরমাণুভাবে পরীক্ষা করা। বন্দরটি যদি ব্যবহার হয় তবে প্রোগ্রামটি বন্দরটি খুলতে ব্যর্থতার সাথে ছেড়ে দেওয়া উচিত।

উদাহরণস্বরূপ, বলুন আপনি জিএনইউ নেটকেট দিয়ে শোনার চেষ্টা করছেন।

#!/bin/bash
read lower_port upper_port < /proc/sys/net/ipv4/ip_local_port_range
while :; do
    for (( port = lower_port ; port <= upper_port ; port++ )); do
        nc -l -p "$port" 2>/dev/null && break 2
    done
done

1
@ লেকেনস্টেইন: আপনি এখানে কোন রেসের অবস্থা দেখতে পাচ্ছেন?
ক্রিস ডাউন

1
এই বন্দরটি উপলব্ধ প্রথম বন্দর ব্যবহার করার চেষ্টা করে। যখন আপনার দুটি সমবর্তী প্রক্রিয়া রয়েছে, তখন যে পোর্টটি সবেমাত্র পরীক্ষিত হয়েছিল তা পুনরায় ব্যবহার করা যেতে পারে। আপনার উত্তরটি পুনরায় পড়ার পরে মনে হচ্ছে আপনি সমস্ত বন্দর শেষ না হওয়া অবধি কোনও উপলব্ধ বন্দরটিতে পুনরায় বাইন্ডিং করার পরামর্শ দিয়েছেন। ধরে নেওয়া যায় যে প্রশ্নে থাকা প্রোগ্রামটি "ব্যবহারের বন্দর" এবং অন্যান্য ত্রুটিগুলির মধ্যে পার্থক্য করতে পারে, এটি ঠিক হওয়া উচিত (যদিও এলোমেলোকরণের কারণে এটি অনির্দেশ্যতার জন্য আরও ভাল করে তুলবে)।
লেকেনস্টেইন

1
@ লেকেনস্টেইন সফল পোর্ট বাধ্যতামূলক ফলাফল কার্নেল EADDRINUSE ফেরত দিলে যদি আপনি আবার চেষ্টা করেন এবং এটি ব্যবহার করেন তবে এটি সম্ভব নয় যে "যে পোর্টটি সবেমাত্র পরীক্ষা করা হয়েছে তা আবার ব্যবহার করা যেতে পারে"।
ক্রিস ডাউন

হ্যাঁ, আমি ভুলভাবে ধরে নিয়েছি যে আপনি লুপটি প্রস্থান করবেন এবং $portআসল প্রোগ্রামটিতে যেমনটি ব্যবহার করবেন while ...; done; program --port $port
লেকেনস্টেইন

ম্যান পৃষ্ঠা থেকে: -p উত্স_port বিশেষাধিকারের বিধিনিষেধ এবং প্রাপ্যতা সাপেক্ষে উত্স পোর্ট এনসি ব্যবহার করা উচিত তা নির্দিষ্ট করে। -L বিকল্পের সাথে মিল রেখে এই বিকল্পটি ব্যবহার করা ত্রুটি।
ভিক্ষু

54

আমার সমাধানটি 0 বন্দরটিতে আবদ্ধ হওয়া, যা কার্নেলকে ip_local_port_range থেকে কোনও পোর্ট বরাদ্দ করতে বলে। তারপরে, সকেটটি বন্ধ করুন এবং আপনার কনফিগারেশনে সেই পোর্ট নম্বরটি ব্যবহার করুন।

এটি কাজ করে কারণ কার্নেল পোর্ট নম্বরগুলি একেবারে না করা পর্যন্ত পুনরায় ব্যবহার করবে বলে মনে হয় না। পরবর্তী পোর্ট 0-এ সংযুক্তিগুলি একটি পৃথক বন্দর নম্বর বরাদ্দ করবে। পাইথন কোড:

import socket

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind(('', 0))
addr = s.getsockname()
print addr[1]
s.close()

এটি কেবলমাত্র একটি বন্দর দেয় যেমন, উদাহরণস্বরূপ। 60123

এই প্রোগ্রামটি 10 ​​000 বার চালান (আপনার এইগুলি একই সাথে চালানো উচিত), এবং আপনি 10 000 বিভিন্ন পোর্ট নম্বর পাবেন। অতএব, আমি মনে করি এটি বন্দরগুলি ব্যবহার করা বেশ নিরাপদ।


20
এখানে একটি ওয়ান-লাইনার রয়েছে (পাইথন 2 এবং পাইথন 3 সহ বৈধ):python -c 'import socket; s=socket.socket(); s.bind(("", 0)); print(s.getsockname()[1]); s.close()'
লেকেনস্টেইন

4
আমি উল্লিখিত পরীক্ষা চালিয়েছি, এবং সমস্ত ফলাফল অনন্য ছিল না। আমার হিস্টোগ্রামটি ছিল:{ 1: 7006, 2: 1249, 3: 151, 4: 8, 5: 1, 6: 1}
বুকজর

2
কোনও চেক যোগ করার কোনও সহজ উপায় কি বন্দরটি ফায়ারওয়াল দ্বারা অবরুদ্ধ নয়, বা কেবল খোলা বন্দরগুলি অনুসন্ধান করে?
লাকাটা

1
@ শেফার্ড আমি বিশ্বাস করি আপনি যদি পূর্ববর্তীটি বন্ধ না করেন তবে আপনি বিভিন্ন বন্দর পাবেন (এবং সেগুলি শেষের দিকে একবারে বন্ধ করুন)।
ফ্র্যাংকলিন ইউ

1
রুবির ২.৩.১ এর জন্য একটি লাইনার:ruby -e 'puts Addrinfo.tcp("", 0).bind { |s| s.local_address.ip_port }'
ফ্রাঙ্কলিন ইউ

12

এক রৈখিক

আমি একটি দুর্দান্ত ওয়ান-লাইনার একসাথে রেখেছি যা দ্রুত উদ্দেশ্য পূরণ করে, একটি স্বেচ্ছাসেবী পরিসরে একটি নির্বিচার সংখ্যক বন্দর দখল করতে দেয় (এখানে এটি পাঠযোগ্যতার জন্য 4 লাইনে বিভক্ত করা হয়েছে):

comm -23 \
<(seq "$FROM" "$TO" | sort) \
<(ss -tan | awk '{print $4}' | cut -d':' -f2 | grep '[0-9]\{1,5\}' | sort -u) \
| shuf | head -n "$HOWMANY"

লাইনে লাইন

commএমন একটি ইউটিলিটি যা দুটি ফাইলের রেখাগুলির সাথে তুলনা করে যা বর্ণমালা অনুসারে বাছাই করতে হবে। এটি তিনটি কলাম আউটপুট করে: প্রথম ফাইলটিতে কেবল প্রদর্শিত লাইনগুলি, কেবল দ্বিতীয়টি এবং সাধারণ লাইনে প্রদর্শিত হয় এমন লাইনগুলি। নির্দিষ্ট করে -23আমরা পরবর্তী কলামগুলি দমন করি এবং কেবল প্রথমটি রাখি। পাঠ্য লাইনের ক্রম হিসাবে প্রকাশিত দুটি সেটগুলির পার্থক্য অর্জন করতে আমরা এটি ব্যবহার করতে পারি। আমি comm এখানে সম্পর্কে শিখেছি ।

প্রথম ফাইলটি পোর্টগুলির পরিসীমা যা আমরা বেছে নিতে পারি। seqথেকে সংখ্যার একটি সাজানো ক্রম উৎপন্ন $FROMকরতে $TO। ফলাফল বর্ণানুক্রমিকভাবে সাজানো হয় (সংখ্যার পরিবর্তে) এবং প্রক্রিয়া প্রতিস্থাপনcomm ব্যবহার করে প্রথম ফাইল হিসাবে পাইপ করা হয় ।

দ্বিতীয় ফাইল পোর্ট সাজানো তালিকা, যে আমরা কল করে প্রাপ্ত ssকমান্ড (সঙ্গে -tঅর্থ বিভিন্ন TCP পোর্ট -aসব অর্থ - প্রতিষ্ঠিত এবং শোনা - এবং -nবলুন, সমাধান করতে চেষ্টা করবেন না, - সাংখ্যিক 22করতে ssh)। এরপরে আমরা কেবলমাত্র চতুর্থ কলামটিই বেছে নিই awk, এতে স্থানীয় ঠিকানা এবং পোর্ট রয়েছে। আমরা ডিলিমিটারের cutসাথে ঠিকানা এবং পোর্ট বিভক্ত করতে ব্যবহার করি :এবং কেবল পরে ( -f2) রাখি । ssএছাড়াও একটি শিরোনাম আউটপুট, যে আমরা grep5 টির চেয়ে বেশি নম্বরের খালি খালি অনুক্রমের জন্য পিং করে পরিত্রাণ পাই We আমরা তারপরে ডুপ্লিকেট ছাড়াই আইংয়ের commপ্রয়োজনীয়তা মেনে sortচলি -u

এখন আমরা যে আমরা করতে পারেন খোলা পোর্ট একটি সাজানো তালিকা আছে, shufতারপর প্রথম দখল করতে fle "$HOWMANY"সঙ্গে বেশী head -n

উদাহরণ

ব্যক্তিগত পরিসরে তিনটি এলোমেলো খোলা পোর্ট ধরুন (49152-65535)

comm -23 <(seq 49152 65535 | sort) <(ss -tan | awk '{print $4}' | cut -d':' -f2 | grep "[0-9]\{1,5\}" | sort -u) | shuf | head -n 3

উদাহরণস্বরূপ ফিরে আসতে পারে

54930
57937
51399

নোট

  • সুইচ -tসঙ্গে -ussপরিবর্তে বিনামূল্যে UDP পোর্ট জন্য।
  • আপনি যদি এলোমেলো পরিবর্তে সংখ্যকভাবে বাছাই করা বন্দরগুলি পেতে পছন্দ shufকরেন sort -nতবে এর সাথে প্রতিস্থাপন করুন


6

দৃশ্যত টিসিপি সংযোগগুলি ল্যাবক্সে ফাইল ডেস্ক্রিপ্টার হিসাবে ব্যাশ / জেডএস-এর সাথে ব্যবহার করা যেতে পারে । নিম্নলিখিত ফাংশনটি সেই কৌশলটি ব্যবহার করে এবং নেটকাট / টেলনেট চালনার চেয়ে দ্রুত হওয়া উচিত।

function EPHEMERAL_PORT() {
    LOW_BOUND=49152
    RANGE=16384
    while true; do
        CANDIDATE=$[$LOW_BOUND + ($RANDOM % $RANGE)]
        (echo "" >/dev/tcp/127.0.0.1/${CANDIDATE}) >/dev/null 2>&1
        if [ $? -ne 0 ]; then
            echo $CANDIDATE
            break
        fi
    done
}

ব্যবহারের নির্দেশাবলী: আউটপুটটিকে একটি ভেরিয়েবলের সাথে আবদ্ধ করুন এবং স্ক্রিপ্টগুলিতে ব্যবহার করুন। উবুন্টু 16.04 এ পরীক্ষিত

root@ubuntu:~> EPHEMERAL_PORT
59453
root@ubuntu:~> PORT=$(EPHEMERAL_PORT)

সাথে কাজ করে ksh93
এফএমপুরফি

আপনি যদি ইউপিওআরটিটি 32768 তে পরিবর্তন করেন তবে আপনি এখনও EG 35835 পেতে পারেন RA সর্বাধিকের চেয়ে বেশি সংখ্যক দ্বারা এটি পরিবর্তনের কোনও প্রভাব নেই। আপনি যেমন কিছু চান $[$LPORT + ($RANDOM % ($UPORT-$LPORT))]
lxs

অন্যথায় যদিও দুর্দান্ত শীতল!
lxs

এটি \nযে কোনও শ্রবণ বন্দরে প্রেরণ করে :) আমি যুক্ত করার পরামর্শ দিই -n। এটি এখনও কোনও সংযোগ খোলার চেষ্টা করবে তবে কিছু না পাঠিয়ে সঙ্গে সঙ্গে সংযোগ বিচ্ছিন্ন করে।
স্টেফ্যান্ট

4

এখানে একটি ক্রস-প্ল্যাটফর্ম, দক্ষ "অনেলিনার" যা সমস্ত ব্যবহারের বন্দরগুলি স্লাপ করে এবং 3000 এর পরে আপনাকে প্রথম উপলভ্য দেয়:

netstat -aln | awk '
  $6 == "LISTEN" {
    if ($4 ~ "[.:][0-9]+$") {
      split($4, a, /[:.]/);
      port = a[length(a)];
      p[port] = 1
    }
  }
  END {
    for (i = 3000; i < 65000 && p[i]; i++){};
    if (i == 65000) {exit 1};
    print i
  }
'

এটি কেবল একটি লাইনে রাখতে আপনি সমস্ত লাইনে যোগ দিতে পারেন। আপনি কি অন্য কিছু পোর্ট নম্বর থেকে প্রথম প্রাপ্তিসাধ্য পেতে চান, এর নিয়োগ পরিবর্তন iমধ্যে forলুপ।

এটি ম্যাক এবং লিনাক্স উভয় ক্ষেত্রেই কাজ করে, এজন্যই [:.]রেজেক্সের প্রয়োজন।


শুধু টিসিপি (6) সকেটগুলি কেন -aএবং কেন দেখার নয় -t?
স্টেফ্যান্ট

এবং যখন আমরা এটিতে আছি, তখন আউটপুট পার্সিং ss -Htnlকরা ভাল হতে পারে (এবং দ্রুত! - আমি এটির যত্ন করি না : পি)।
স্টেফ্যান্ট

@ স্টেফ্যান্ট বিএসডি নেটস্যাট নেই -t, কমপক্ষে একটি যা অ্যাপল জাহাজে নিয়ে আসে, এবং ম্যাকওএস- ssতে উপস্থিত হয় না। netstat -alnএমনকি সোলারিসে কাজ করে।
w00t

3

লিনাক্স-এ আপনি এমন কিছু করতে পারেন:

ss -tln | 
  awk 'NR > 1{gsub(/.*:/,"",$4); print $4}' |
  sort -un |
  awk -v n=1080 '$0 < n {next}; $0 == n {n++; next}; {exit}; END {print n}'

1080 এর উপরে প্রথম নিখরচায় পোর্টটি সন্ধান ssh -Dকরতে Note নোটটি লুপব্যাক ইন্টারফেসের সাথে আবদ্ধ হবে তা নোট করুন যাতে কোনও সকেটের অন্য কোনও ঠিকানায় আবদ্ধ থাকলে আপনি থিওরি পোর্ট 1080 ব্যবহার করতে পারেন use আরেকটি উপায় হ'ল এটি চেষ্টা করে বেঁধে রাখা:

perl -MSocket -le 'socket S, PF_INET, SOCK_STREAM,getprotobyname("tcp");
  $port = 1080;
  ++$port until bind S, sockaddr_in($port,inet_aton("127.1"));
  print $port'

এটি অবশ্য বন্দরটি খোলার চেষ্টা এবং এটি ব্যবহার করার মধ্যে একটি দৌড় শর্ত জড়িত।
ক্রিস ডাউন

@ ক্রিসডাউন, প্রকৃতপক্ষে, তবে ssh -D, এর চেয়ে ভাল বিকল্প আমি দেখতে পাচ্ছি না। -O forwardবিকল্প sshএকটি ত্রুটি ফেরত দেয় না যখন এগিয়ে ব্যর্থ হয়।
স্টাফেন চেজেলাস

3

এটি আমি ব্যবহার করা সংস্করণ:

while
  port=$(shuf -n 1 -i 49152-65535)
  netstat -atun | grep -q "$port"
do
  continue
done

echo "$port"

কমান্ডটি shuf -n 1 -i 49152-65535আপনাকে গতিশীল পরিসরে একটি "এলোমেলো" পোর্ট দেয়। যদি এটি ইতিমধ্যে ব্যবহৃত হয়, তবে এই ব্যাপ্তির অন্য একটি বন্দরের চেষ্টা করা হবে।

কমান্ডটি netstat -atunসমস্ত (-a) টিসিপি (-t) এবং ইউডিপি (-u) পোর্টকে হোস্ট-নেম (-n) নির্ধারণের জন্য সময় নষ্ট না করে তালিকাভুক্ত করে।


1

এটি আমার .Bashrc- এ থাকা একটি ফাংশনের অংশ যা গতিশীলভাবে এসএসএইচ টানেলগুলি তৈরি করে এবং কোনও বন্দরকে একটি ব্যাপ্তিতে ব্যবহার করার চেষ্টা করে:

   lps=( 7002 7003 7004 7005 7006 7007 7008 7009 7010 7011 )
   lp=null

   # find a free listening port
   for port in ${lps[@]}; do
      lsof -i -n -P |grep LISTEN |grep -q ":${port}"
      [ $? -eq 1 ] && { lp=$port; break; }
   done
   [ "$lp" = "null" ] && { echo "no free local ports available"; return 2; }
   return $port

YMMV


1

এই পুরাতন শখ ঘোড়ায় আরও একটি রান:

function random_free_tcp_port {
  local ports="${1:-1}" interim="${2:-2048}" spacing=32
  local free_ports=( )
  local taken_ports=( $( netstat -aln | egrep ^tcp | fgrep LISTEN |
                         awk '{print $4}' | egrep -o '[0-9]+$' |
                         sort -n | uniq ) )
  interim=$(( interim + (RANDOM % spacing) ))

  for taken in "${taken_ports[@]}" 65535
  do
    while [[ $interim -lt $taken && ${#free_ports[@]} -lt $ports ]]
    do
      free_ports+=( $interim )
      interim=$(( interim + spacing + (RANDOM % spacing) ))
    done
    interim=$(( interim > taken + spacing
                ? interim
                : taken + spacing + (RANDOM % spacing) ))
  done

  [[ ${#free_ports[@]} -ge $ports ]] || return 2

  printf '%d\n' "${free_ports[@]}"
}

এই কোড এর বিশুদ্ধরূপে পোর্টেবল ব্যবহার করে netstat, egrep, awk, & অল। মনে রাখবেন যে শুরুতে নেওয়া পোর্টগুলির একটি তালিকা পেতে কেবলমাত্র বাহ্যিক কমান্ডগুলিতে কল জারি করা হয়। এক বা একাধিক বিনামূল্যে বন্দরগুলির জন্য অনুরোধ করতে পারে:

:;  random_free_tcp_port
2070
:;  random_free_tcp_port 2
2073
2114

এবং একটি নির্বিচারে বন্দরে শুরু করুন:

:;  random_free_tcp_port 2 10240
10245
10293

1
while port=$(shuf -n1 -i $(cat /proc/sys/net/ipv4/ip_local_port_range | tr '\011' '-'))
netstat -atun | grep -q ":$port\s" ; do
    continue
done
echo $port

উপরের অন্যান্য উত্তরগুলি থেকে আমার সংমিশ্রণ। এটা নাও:

Shuf -n1 দিয়ে আমরা / proc / sys / নেট / ipv4 / ip_local_port_range এ রেঞ্জ (-i) থেকে একটি এলোমেলো নম্বর নিই। shuf ড্যাশ সহ বাক্য গঠন প্রয়োজন, তাই আমরা ড্যাশটিতে ট্যাব পরিবর্তন করতে ট্র ব্যবহার করি use

পরের উইয়ে আমাদের সকল (-a) টিসিপি এবং ইউডিপি (-u -t) সংযোগগুলি (-n) দেখানোর জন্য নেটস্পট ব্যবহার করুন, যদি আমরা আমাদের এলোমেলো বন্দর $ বন্দরটি খুঁজে পাই (এটি দিয়ে শুরু করুন: এবং ডাব্লাইট স্পেসে শেষ করুন) ( । গুলি) এর পরে আমাদের অন্য একটি পোর্ট দরকার এবং তাই চালিয়ে যান El অন্যথায় (গ্রেপ-কি-এর একটি রিটারকোড থাকে> 0) আমরা লুপটি রেখেছিলাম এবং $ বন্দরটি সেট হয়ে যায়।


1

যদি অজগর শুয়ে থাকে তবে আমি এটি করতাম:

port="$(python -c 'import socket; s=socket.socket(); s.bind(("", 0)); print(s.getsockname()[1])')";
echo "Unused Port: $port"


0

আমার এটি গ্রহণ করুন ... ফাংশনটি nএকটানা ফ্রি পোর্টগুলি সন্ধান করার চেষ্টা করে :

#!/bin/bash

RANDOM=$$

# Based on 
# https://unix.stackexchange.com/a/55918/41065
# https://unix.stackexchange.com/a/248319/41065
find_n_ports () {
    local n=$1
    RANDOM=$$
    read lower_port upper_port < /proc/sys/net/ipv4/ip_local_port_range
    local tries=10
    while [ $((tries--)) -gt 0 ]; do
        # Sleep for 100 to 499 ms
        sleep "0.$((100+$RANDOM%399))"
        local start="`shuf -i $lower_port-$(($upper_port-$n-1)) -n 1`"
        local end=$(($start+$n-1))
        # create ss filter for $n consecutive ports starting with $start
        local filter=""
        local ports=$(seq $start $end)
        for p in $ports ; do
            filter="$filter or sport = $p"
        done
        # if none of the ports is in use return them
        if [ "$(ss -tHn "${filter# or}" | wc -l)" = "0" ] ; then
            echo "$ports"
            return 0
        fi
    done
    echo "Could not find $n consecutive ports">&2
    return 1
}

ports=$(find_n_ports 3)
[ $? -ne 0 ] && exit 1
exit 0
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.