Broker testleri

MQTT ağ sorunlarını teşhis etmek: DNS, firewall ve proxy

MQTT istemciniz broker'a neden ulaşamıyor? DNS, TCP yönlendirme, firewall, kurumsal proxy ve TLS araya girmesini katman katman gerçek komutlarla test edin.

Güncellendi · 9 dk okuma

MQTT ağ sorunlarını teşhis etmek: DNS, firewall ve proxy

Bir MQTT istemcisi belirsiz bir "connection failed" hatasıyla başarısız olduğunda sebep nadiren MQTT'nin kendisidir. Genellikle altındaki dört katmandan biridir: DNS broker adını çözemedi, TCP port'a ulaşamadı, bir proxy veya firewall bağlantıyı sessizce yuttu ya da TLS araya girilerek incelendi ve sertifika artık eşleşmiyor. Bu katmanları sırayla — DNS → TCP → TLS → MQTT — test ederek bozuk olanı birkaç dakikada bulursunuz.

Bu rehber her katman için kesin komutu, her arızanın ürettiği hata mesajlarını ve zincirin tamamını çalıştırıp nerede koptuğunu söyleyen bir Python script'ini veriyor.

Önce hata mesajını okuyun

Hata metni hangi katmana bakmanız gerektiğini zaten söyler. En çok aranan mesajlar şunlardır:

HataKatmanOlası sebep
getaddrinfo ENOTFOUND broker.connectmq.com (Node.js)DNSHost adında yazım hatası, DNS sunucusu yok, split-horizon DNS
[Errno -2] Name or service not known (Python, Linux)DNSYukarıdakiyle aynı
[Errno 8] nodename nor servname provided, or not known (Python, macOS)DNSYukarıdakiyle aynı
getaddrinfo EAI_AGAINDNSResolver erişilemiyor veya geçici olarak hata veriyor
connect ETIMEDOUT / TimeoutError: timed outTCP / firewallPaketler yolda düşürülüyor, yanlış IP, engellenmiş port
connect ECONNREFUSED / [Errno 111] Connection refusedTCPHost erişilebilir ama o portta dinleyen yok
Bağlandıktan hemen sonra ECONNRESETProxy / firewallAradaki bir cihaz bağlantıyı inceledikten sonra kesti
certificate verify failed: unable to get local issuer certificateTLSEksik CA paketi veya TLS araya girmesi
self signed certificate in certificate chainTLSTrafiği yeniden imzalayan kurumsal proxy

Zaten reason code içeren bir CONNACK alıyorsanız ağ sağlamdır; sorun kimlik doğrulama veya yapılandırmadadır — reason code referansına bakın.

Katman 1: DNS çözümleme

Adın çözümlendiğini ve her yerde aynı adreslere çözümlendiğini kontrol edin:

Broker adını çözümleyin
dig +short broker.connectmq.com A
dig +short broker.connectmq.com AAAA

# Split-horizon veya eski kayıtları yakalamak için genel bir resolver ile karşılaştırın
dig +short broker.connectmq.com @1.1.1.1

# Windows
nslookup broker.connectmq.com

Nelere bakmalı:

  • Yanıt yok — ad bu resolver'da mevcut değil. Yazımı ve bir VPN'in ya da kurumsal DNS'in dış zone'ları ezip ezmediğini kontrol edin.
  • Farklı yanıtlar (sizin resolver'ınız ile genel resolver arasında) — split-horizon DNS, broker taşımasından sonra önbellekte kalmış eski kayıt veya engelleme sayfası IP'si döndüren bir DNS filtresi.
  • AAAA kaydı var ama IPv6 rotası yok — istemci önce IPv6 dener ve geri dönene kadar takılı kalır. MQTT IPv6 sorunları yazısına bakın.

Container'ların içinde DNS host'tan değil, container runtime'dan gelir. Host sonucunun geçerli olduğunu varsaymadan önce aynı dig komutunu container içinde (docker exec -it app sh) çalıştırın.

Katman 2: TCP erişilebilirliği ve yönlendirme

Çözümleme çalışıyor; şimdi kullanabileceğiniz her MQTT portuna ham bir TCP bağlantısı açın:

MQTT portlarını test edin
nc -vz -w 5 broker.connectmq.com 1883   # TCP üzerinden MQTT
nc -vz -w 5 broker.connectmq.com 8883   # TLS üzerinden MQTT
nc -vz -w 5 broker.connectmq.com 8084   # Güvenli WebSockets üzerinden MQTT
Windows PowerShell
Test-NetConnection broker.connectmq.com -Port 8883

Zaman aşımı ile reddedilme arasındaki fark, ağ hata ayıklamasındaki en faydalı sinyaldir:

  • succeeded / TcpTestSucceeded : True — yol açık; TLS'e geçin.
  • Connection refused — host'a ulaştınız ama orada dinleyen yok. Yanlış port ya da broker kapalı.
  • Takılıp sonra zaman aşımına düşüyor — sizinle broker arasındaki bir şey paketleri düşürüyor. Neredeyse her zaman bir firewall'dur.

Paketlerin nerede durduğunu görmek için rotayı ICMP ile değil (birçok ağ onu farklı ele alır), gerçek port üzerinden izleyin:

TCP yolunu izleyin
sudo traceroute -T -p 8883 broker.connectmq.com   # Linux
mtr --tcp --port 8883 broker.connectmq.com        # mtr kuruluysa

İz kendi gateway'inizde veya ilk kurumsal atlamada bitiyorsa engel yereldir. Çok uzakta bitiyorsa sorun daha ileride ya da broker'ın kenarındadır. Port kontrollerinin tam anlatımı bir MQTT portunun açık olup olmadığını test etmek yazısında, standart port numaraları ise MQTT portları yazısında.

Katman 3: Firewall'lar ve proxy'ler

Ofis, otel ve bulut ağları çoğu zaman yalnızca açık bir proxy üzerinden giden HTTP(S) trafiğine izin verir. MQTT istemcileri varsayılan olarak HTTP_PROXY değişkenini okumaz, bu yüzden doğrudan bağlantı basitçe zaman aşımına düşer.

Önce yapılandırılmış bir proxy olup olmadığını öğrenin:

Proxy ayarlarını arayın
env | grep -i _proxy
# Windows: netsh winhttp show proxy

Ardından proxy'nin HTTP CONNECT ile broker portuna tünel açıp açmadığını kontrol edin:

HTTP proxy üzerinden tünel
nc -X connect -x proxy.example.corp:3128 -vz broker.connectmq.com 8883

Proxy 8883'e CONNECT'i reddedip 443'e izin veriyorsa iki seçeneğiniz var: proxy'nin izin verdiği bir portta güvenli WebSockets üzerinden MQTT kullanmak ya da ağ ekibinden broker host'una izin vermesini istemek. Tarayıcı tabanlı istemciler sistem proxy'sinden otomatik geçer; online MQTT istemcisinin yerel istemcinin başarısız olduğu ağlarda sık sık çalışmasının sebebi budur. Daha fazla strateji için kurumsal firewall arkasında MQTT ve 443 portu üzerinden MQTT yazılarına bakın.

Katman 4: TLS ve araya girme

TCP portu açık ama TLS başarısız. İstemcinin gerçekte aldığı sertifikaya bakın:

Sertifika zincirini inceleyin
openssl s_client -connect broker.connectmq.com:8883 \
  -servername broker.connectmq.com -showcerts </dev/null 2>/dev/null \
  | openssl x509 -noout -subject -issuer -dates

issuer satırını telefon hotspot'u veya ev ağından aldığınız sonuçla karşılaştırın. Ofiste yayıncı olarak şirketinizin adı ya da bir güvenlik ürünü görünüyorsa, TLS inceleyen bir proxy bağlantıyı yeniden imzalıyordur. MQTT istemciniz bunu certificate verify failed veya self signed certificate in certificate chain ile reddeder — ve bu doğru davranıştır.

Tercih sırasına göre çözümler:

  1. Broker host'unun TLS incelemesinden muaf tutulmasını isteyin (MQTT HTTP değildir ve birçok inceleme ürünü onu zaten bozar).
  2. Politika incelemeyi zorunlu kılıyorsa kurumsal kök CA'yı istemcinin güven deposuna ekleyin — sertifika doğrulamasını asla kapatmayın.
  3. İstemcinin SNI gönderdiğinden emin olun (yukarıdaki -servername): SNI olmadan bazı endpoint'ler farklı bir sertifika döndürür ve bu hostname mismatch hatalarına yol açar.

Handshake hata vermek yerine takılıp kalıyorsa, özellikle VPN üzerinde, bir MTU sorunundan şüphelenin: küçük paketler geçer ama büyük sertifika mesajı düşürülür. Arayüzde daha küçük bir MTU ile test etmek bunu doğrular. Genel TLS hataları MQTT TLS handshake failed yazısında ele alınıyor.

Zincirin tamamını tek script ile çalıştırın

Bu script (Python 3.8+, paho-mqtt 2.x) her katmanı sırayla test eder, ilk hatada durur ve her adımın süresini yazdırır:

netcheck.py
import os, socket, ssl, sys, time
import paho.mqtt.client as mqtt

HOST, PORT = "broker.connectmq.com", 8883

def dns():
    infos = socket.getaddrinfo(HOST, PORT, proto=socket.IPPROTO_TCP)
    return ", ".join(sorted({i[4][0] for i in infos}))

def tcp():
    with socket.create_connection((HOST, PORT), timeout=5) as s:
        return f"connected to {s.getpeername()[0]}"

def tls():
    ctx = ssl.create_default_context()
    with socket.create_connection((HOST, PORT), timeout=5) as raw:
        with ctx.wrap_socket(raw, server_hostname=HOST) as s:
            issuer = dict(x[0] for x in s.getpeercert()["issuer"])
            return f"{s.version()}, issuer: {issuer.get('organizationName')}"

def mqtt_connect():
    result = {}
    c = mqtt.Client(mqtt.CallbackAPIVersion.VERSION2, protocol=mqtt.MQTTv5)
    c.on_connect = lambda cl, ud, flags, reason, props: result.setdefault("rc", reason)
    if os.getenv("MQTT_USER"):
        c.username_pw_set(os.getenv("MQTT_USER"), os.getenv("MQTT_PASS"))
    c.tls_set()
    c.connect(HOST, PORT, keepalive=30)
    c.loop_start()
    for _ in range(50):
        if "rc" in result:
            break
        time.sleep(0.1)
    c.disconnect()
    c.loop_stop()
    if "rc" not in result:
        raise TimeoutError("no CONNACK within 5 s")
    if result["rc"].is_failure:
        raise RuntimeError(f"CONNACK: {result['rc']}")
    return f"CONNACK: {result['rc']}"

for name, step in [("DNS", dns), ("TCP", tcp), ("TLS", tls), ("MQTT", mqtt_connect)]:
    start = time.perf_counter()
    try:
        info = step()
    except Exception as e:
        print(f"FAIL  {name:<5} {type(e).__name__}: {e}")
        sys.exit(1)
    print(f"OK    {name:<5} {(time.perf_counter() - start) * 1000:6.0f} ms  {info}")

Sağlıklı bir çalıştırma dört OK satırı yazdırır. Bir hata size katmanı ve kesin exception'ı söyler; bu da doğrudan yazının başındaki tabloya karşılık gelir. Script'i sorunu yaşayan makinede çalıştırın — başka bir ağdaki dizüstü bilgisayar, başarısız olan cihaz hakkında hiçbir şey kanıtlamaz.

Düzeltmeyi doğrulayın

DNS'i, firewall kurallarını veya proxy ayarlarını değiştirdikten sonra değişikliğe güvenmek yerine uçtan uca doğrulayın:

  1. Etkilenen makinede netcheck.py'yi yeniden çalıştırın ve dört katmanın da geçtiğini doğrulayın.
  2. Online istemcide bir test topic'ine abone olun ve etkilenen cihazdan o topic'e publish edin.
  3. Bağlantıyı tahmin ettiğiniz firewall zaman aşımından daha uzun süre boşta bırakın ve mesajların hâlâ geldiğini kontrol edin.

Teslimatı test etmek için online istemciyi açın

Ağ sorunları katmanlara ayırana kadar rastgele görünür. Adı çözümleyin, socket'i açın, sertifikayı inceleyin, ardından MQTT konuşun — ilk başarısız olan adım düzeltmeniz gerekendir ve hata mesajı genellikle onu zaten söyler.

Sıkça sorulan sorular

MQTT istemcim neden evde çalışıyor da ofiste çalışmıyor?

Kurumsal ağlar genellikle 1883 ve 8883 gibi giden portları engeller, trafiği bir HTTP proxy üzerinden geçmeye zorlar ya da TLS'i inceler. Her katmanı ofis ağından test edin: DNS, ham bir TCP bağlantısı, TLS sertifikasının yayıncısı ve ardından MQTT. 443 portu üzerinden MQTT over WebSockets çoğu zaman çıkış yoludur.

Bir firewall'un MQTT trafiğini düşürüp düşürmediğini nasıl anlarım?

Paketleri düşüren bir firewall zaman aşımına (ETIMEDOUT, 'timed out') yol açar; erişilebilir bir host'taki kapalı port ise anında 'Connection refused' ile yanıt verir. Port'a karşı nc -vz veya Test-NetConnection çalıştırın ve aynı host'taki başka bir portla karşılaştırın.

Ağımda TLS araya girmesini (interception) nasıl tespit ederim?

Broker'a karşı openssl s_client çalıştırıp sertifika yayıncısını yazdırın. Yayıncı genel bir CA yerine şirketinizin ya da bir güvenlik ürününün CA'sı ise bağlantı araya girilerek inceleniyordur ve istemciniz bu CA'ya güvenmedikçe sertifika doğrulamasında başarısız olur.