สำรองการเชื่อมต่ออินเทอร์เน็ตสำหรับกระบวนการเฉพาะ

Aug 17 2020

ฉันต้องการเพิ่มการเชื่อมต่ออินเทอร์เน็ตสำรองข้อมูลสำรองไปยังเซิร์ฟเวอร์ Linux ของฉัน ฉันวางแผนที่จะใช้โมเด็ม USB LTE เพื่อจุดประสงค์นี้

เนื่องจากการเชื่อมต่อเซลลูลาร์นี้จะถูกตรวจสอบฉันจึงต้องการ จำกัด ปริมาณข้อมูลที่สามารถใช้งานได้ให้เหลือน้อยที่สุดเท่าที่จำเป็น

ฉันมีแอปพลิเคชันเซิร์ฟเวอร์แบบกำหนดเองที่สามารถเปลี่ยนแปลงได้ มีงานบางอย่างที่การเชื่อมต่ออย่างต่อเนื่องเป็นสิ่งสำคัญและงานอื่น ๆ ที่การหยุดทำงานไม่สำคัญ

ฉันกำลังจินตนาการถึงสิ่งนี้:

  • เซิร์ฟเวอร์จำเป็นต้องส่งคำขอ HTTP API ภายนอก ความพยายามครั้งแรกเกิดขึ้นบนเส้นทางเริ่มต้นของระบบ (เช่น eth0 การเชื่อมต่ออินเทอร์เน็ตหลัก)
  • หากคำขอล้มเหลวหรือหมดเวลาให้ลองส่งคำขออีกครั้งผ่านอินเทอร์เฟซ LTE

ควรส่งเฉพาะทราฟฟิกที่เซิร์ฟเวอร์ของฉันต้องการส่งผ่าน LTE อย่างชัดเจนเท่านั้นที่ควรส่งผ่าน LTE การรับส่งข้อมูลอื่น ๆ จากส่วนใดส่วนหนึ่งของระบบไม่ควรผ่าน LTE

  • โดยเฉพาะอย่างยิ่งฉันจะใช้localAddressตัวเลือกซ็อกเก็ตของโหนดเพื่อระบุว่าควรส่งคำขอผ่าน LTE
  • ฉันจะแน่ใจได้อย่างไรว่าการรับส่งข้อมูลอื่น ๆ จะไม่สิ้นสุดการกำหนดเส้นทางผ่านอินเทอร์เฟซ LTE (แม้ว่า eth0 จะหยุดทำงาน)
  • แล้วการแก้ปัญหา DNS ล่ะ

คำตอบ

josh3736 Sep 01 2020 at 03:53

ฉันลงเอยด้วยการกำหนดค่าตารางเส้นทางสำรองและกฎนโยบายการกำหนดเส้นทางสำหรับที่อยู่ต้นทางของอินเทอร์เฟซสำรอง

โมเด็ม USB LTE ที่ฉันนำเสนอเป็นอุปกรณ์ NDIS ดังนั้นจึงแสดงขึ้นeth1พร้อมกับ IP ที่ 192.168.0.190 และทำการกำหนดเส้นทาง NAT ภายใน ฉันได้กำหนดค่าeth1ด้วย IP แบบคงที่และกำหนดเส้นทางด้วยตนเองแล้ว

  1. การกำหนดค่าเริ่มต้นใช้ DHCP ดังนั้นให้ปิดอินเทอร์เฟซและตรวจสอบให้แน่ใจว่าได้ลบเส้นทางที่เพิ่มโดยอัตโนมัติ

  2. เพิ่มการกำหนดค่า IP แบบคงที่สำหรับอินเทอร์เฟซและเรียกใช้

  3. เพิ่มรายการในตารางเส้นทางสำรอง (ฉันได้เลือกไว้1) สำหรับซับเน็ตและเกตเวย์เริ่มต้น

    # ip route add 192.168.0.0/24 dev eth1 src 192.168.1.190 table 1
    # ip route add default via 192.168.0.1 table 1
    
  4. ตั้งค่ากฎนโยบายการกำหนดเส้นทางเพื่อให้แอปที่ใช้ 192.168.1.190 เป็นที่อยู่ต้นทางอย่างชัดเจนจะใช้ตารางเส้นทาง 1 แทนค่าเริ่มต้น

    # ip rule add from 192.168.0.190/32 table 1
    # ip rule add to 192.168.0.190/32 table 1
    

ณ จุดนี้คุณควรทดสอบการเชื่อมต่อได้

$ curl https://wtfismyip.com/text 1.2.3.4 # primary ISP external IP $ curl --interface 192.168.0.190 https://wtfismyip.com/text
5.6.7.8  # backup LTE external IP

หากทุกอย่างดูดีให้กำหนดค่าถาวร ฉันเพิ่มไปที่/etc/network/interfaces:

iface eth1 inet static
        address 192.168.0.190
        netmask 255.255.255.0
        post-up ip route add 192.168.0.0/24 dev eth1 src 192.168.0.190 table 1
        post-up ip route add default via 192.168.0.1 table 1
        post-up ip rule add from 192.168.0.190/32 table 1
        post-up ip rule add to 192.168.0.190/32 table 1

ตอนนี้เฉพาะแอพที่เชื่อมโยงกับ 192.168.0.190 อย่างชัดเจนเมื่อทำการเชื่อมต่อขาออกเท่านั้นที่จะถูกส่งผ่านการเชื่อมต่อสำรอง การรับส่งข้อมูลอื่น ๆ ทั้งหมดจะถูกกำหนดเส้นทางไปeth0(หรืออะไรก็ตามที่กำหนดไว้ในmainตารางการกำหนดเส้นทาง [ค่าเริ่มต้น])

เป็นไปได้ว่าคุณมีบางอย่างที่ระบุ IP ที่มีอยู่ทั้งหมดและพยายามส่งการรับส่งข้อมูลจากพวกเขาซึ่งอาจส่งผลให้เกิดการรับส่งข้อมูลที่ไม่คาดคิดผ่านการเชื่อมต่อสำรอง แต่ก็ไม่น่าเป็นไปได้ ฉันไม่ได้สังเกตการจราจรดังกล่าว

โปรดทราบว่าสิ่งนี้ไม่ได้กล่าวถึงการแก้ปัญหา DNS ในสถานการณ์ที่การเชื่อมต่อหลักออฟไลน์คุณอาจโชคดีและได้รับการค้นหาจากแคช แต่ก็ไม่ดีที่จะพึ่งพา ฉันจะไม่กำหนดค่าตัวแก้ไขทั้งระบบเพื่อส่งคำขอผ่านอินเทอร์เฟซ LTE ด้วย แต่แอปของคุณสามารถจัดการความละเอียด DNS ได้ด้วยตนเองเมื่อทำการร้องขอการสำรองข้อมูล


ด้วยโหนดการร้องขอ HTTP (หรือการเชื่อมต่อ TCP ใด ๆ ) จากที่อยู่ต้นทางที่ระบุเป็นเรื่องง่าย เพียงระบุlocalAddressตัวเลือกเช่น:

https.get('https://wtfismyip.com/text', { localAddress: '192.168.0.190' }, …);

การแก้ไขการค้นหา DNS นั้นยุ่งยากกว่าเล็กน้อย lookupตัวเลือกยังมีอยู่ซึ่งจะช่วยให้คุณสามารถแทนที่กระบวนการแก้ปัญหา DNS เริ่มต้น คุณสามารถใช้แบบกำหนดเองdns.Resolverเพื่อทำการค้นหา แต่น่าเสียดายที่โหนดไม่ได้มีวิธีการที่จะระบุแหล่งที่อยู่สำหรับการค้นหา DNS ที่ดังนั้นฉันเพิ่มมัน เมื่อเข้าที่แล้วคุณสามารถประกอบชิ้นส่วนเข้าด้วยกัน:

const resolver = new dns.Resolver();
resolver.setServers(['8.8.8.8']);
resolver.setLocalAddress('192.168.0.190'); // requires node > v15.0.0

https.get('https://wtfismyip.com/text', {
  localAddress: '192.168.0.190',
  lookup: function(hostname, opts, cb) {
    resolver.resolve(hostname, function(err, records) {
      if (err) cb(err);
      else if (!records[0]) cb(new Error('Missing DNS record'));
      else cb(null, records[0], 4);
    });
  }
}, function(res) { … });