7 मिनट पढ़ें

Approval targets के लिए IPv6 address normalization

IPv6 address normalization से bracketed URLs, mapped IPv4 forms, compressed zeros और zones में approval targets पढ़ने और तुलना करने में आसान होते हैं।

Approval targets के लिए IPv6 address normalization

ऐसी approval screen जो raw IPv6 string दिखाती है, वह समय के दबाव में किसी व्यक्ति से parser का काम करवाती है। यह डिजाइन की गलती है। सिस्टम को अनुरोध को typed endpoint में parse करना चाहिए, अस्पष्टता को अस्वीकार करना चाहिए, typed value की तुलना करनी चाहिए और एक ऐसा स्थिर रूप दिखाना चाहिए जिसे व्यक्ति अगले अनुरोध पर पहचान सके।

IPv6 notation हमलावरों और सामान्य software, दोनों को एक ही destination को अलग दिखाने के कई तरीके देता है: compressed zero fields, leading zeros, URLs में जरूरी brackets, embedded IPv4 tail और interface zones। इससे IPv6 संदिग्ध नहीं हो जाता। इसका मतलब बस इतना है कि approval target को उस field से अधिक सख्ती से संभालना होगा जिसमें संयोग से hostname आ गया हो।

एक पते के कई टेक्स्ट रूप हो सकते हैं

2001:db8:0:0:0:0:0:9, 2001:0db8::9 और 2001:db8::9 एक ही unscoped IPv6 address पहचानते हैं। अगर आपका approval card एक string स्टोर करता है और बाद का अनुरोध दूसरा रूप देता है, तो string comparison उन्हें अलग बताएगा। अगर आपकी allowlist एक spelling स्वीकार करती है, लेकिन audit search दूसरे रूप की अपेक्षा करती है, तो जरूरत के समय operators को रिकॉर्ड का सिरा नहीं मिलेगा।

IPv6 में आठ 16-bit fields होते हैं। हर field में लेखक शुरुआती शून्य छोड़ सकता है, फिर सभी-शून्य fields की एक लगातार श्रृंखला को :: से बदल सकता है। :: marker इंसानों के लिए सुविधाजनक है, मगर इससे यह जानकारी हट जाती है कि लेखक ने कितने fields छोड़े। Parser छूटे fields फिर से बनाता है और equality decision के लिए मायने रखने वाला एकमात्र रूप लौटाता है: address के 16 bytes।

यह अंतर अक्सर धुंधला हो जाता है: canonical text समीक्षा के लिए है, जबकि parsed bytes comparison के लिए हैं। Canonicalization अपने आप authorization नहीं है। यह बस सुनिश्चित करता है कि व्यक्ति को दिखाया गया रूप कॉलर की spelling पर निर्भर न हो।

इन्हें अलग data items मानें:

  • raw_input: कॉलर से मिला exact host text और उसके आसपास का authority syntax
  • address: strict parsing के बाद 16 bytes
  • scope_id: input में वैध रूप से दिया गया interface scope
  • display_host: typed address से बनाया गया canonical string
  • port, scheme और request details: असल कार्रवाई को बताने वाले fields

Audit record में raw input रखें। इससे पता चलता है कि agent ने क्या मांगा था। इसे comparison token की तरह इस्तेमाल न करें और न इसे screen पर दिखने वाली अकेली चीज बनाएं।

URI brackets syntax हैं, host का हिस्सा नहीं

URI authority के भीतर IPv6 literal को brackets में लिखना जरूरी है, क्योंकि colons पहले ही host और port को अलग करते हैं। RFC 3986 यह रूप बताता है: https://[2001:db8::9]:8443/v1/jobs। पता 2001:db8::9 है, brackets URI parser को बताते हैं कि host कहां समाप्त होता है।

इस नियम से एक आम विफलता पैदा होती है। कोई developer [2001:db8::9] को address parser में देता है, rejection मिलता है, वह काम चलने तक characters हटाता है और बाद में malformed authority स्वीकार हो जाती है क्योंकि दोनों parsers की सहमति नहीं रहती। इसी bug का दूसरा रूप address के साथ brackets भी स्टोर कर देता है, इसलिए एक record में [2001:db8::9] और दूसरे में 2001:db8::9 होता है। वे कभी एक ही storage field तक पहुंचने ही नहीं चाहिए थे।

जिस grammar boundary पर value आई थी, वहीं parse करें। HTTP target के लिए पहले पूरे URI को standards-aware URI parser से parse करें। उसी parser के अनुसार उसका host, port, scheme, path और query निकालें। फिर URI brackets हटाकर केवल host value को IPv6 parser में भेजें। सीधे SSH host argument के लिए SSH command interface में बताए गए grammar का प्रयोग करें, उसे URI मानने का दिखावा न करें।

क्रम मायने रखता है। इस अनुरोध को देखें:

https://[2001:0db8:0:0:0:0:0:9]:8443/admin

सही internal result का रूप यह है:

kind: ipv6
address: 20010db8000000000000000000000009
scope_id: null
display_host: 2001:db8::9
scheme: https
port: 8443
path: /admin

अब approval UI https://[2001:db8::9]:8443/admin कह सकता है। उसे इसे चुपचाप 2001:db8::9 में नहीं बदलना चाहिए, क्योंकि port और path उस चीज का हिस्सा हैं जिसका उपयोगकर्ता मूल्यांकन कर रहा है। उलटे, सिर्फ इसलिए कि वह पहले आया था, कॉलर की padded spelling भी नहीं रखनी चाहिए।

Bare literal में brackets नहीं होते। IPv6 literal वाली URI authority में brackets होते हैं। इस नियम को सीमित और अनुमान लगाने योग्य रखें।

Canonical display को RFC 5952 का पालन करना चाहिए

RFC 5952 lowercase hexadecimal, field में कोई leading zero नहीं और zero fields की सबसे लंबी लगातार श्रृंखला के लिए :: की सलाह देता है। जब दो zero runs की लंबाई बराबर हो, तो यह पहले को चुनता है। यह यह भी कहता है कि zero का एक अकेला field :: का इस्तेमाल न करे। ये नियम मानव-पठनीय रूप को स्थिर परिणाम देते हैं।

उदाहरण के लिए, इन values को इस तरह normalize करें:

2001:0DB8:0000:0000:0000:0000:0000:0009  ->  2001:db8::9
2001:db8:0:1:0:0:0:1                    ->  2001:db8:0:1::1
2001:db8:0:1:0:0:0:0                    ->  2001:db8:0:1::
2001:db8:0:1:0:0:0:2                    ->  2001:db8:0:1::2
0:0:0:0:0:0:0:1                         ->  ::1

Standard की सलाह दिखने से अधिक उपयोगी है। यह operators को logs में खोजने के लिए एक ही spelling देता है और कॉलर को 2001:0DB8::9 को नया destination दिखाने से रोकता है, जब 2001:db8::9 पहले ही मंजूर हो चुका हो।

Colons पर split करके और empty strings गिनकर अपना formatter न लिखें। IPv4 tail form, malformed double compression और scope syntax इस तरीके को नाजुक बना देते हैं। जिस language में कार्रवाई होती है, उसमें परीक्षण किया हुआ IPv6 parser इस्तेमाल करें, उसका 16-byte output रखें और उन्हीं bytes से format बनाएं। Formatter को RFC 5952 examples और बराबर लंबाई वाले zero runs के cases से जांचें।

RFC 5952 के बारे में जरूरत से ज्यादा दावा भी न करें। यह सुझाया गया text representation बताता है। यह तय नहीं करता कि ::ffff:192.0.2.7 और 192.0.2.7 को समान authorization मिलना चाहिए या नहीं। यह वास्तविक परिणामों वाला product decision है।

IPv4-mapped forms के लिए comparison rule स्पष्ट होना चाहिए

::ffff:192.0.2.7 एक IPv4-mapped IPv6 address है। अंतिम 32 bits में IPv4 address होता है और उससे पहले का pattern mapped form पहचानता है। जब application IPv6 socket पर IPv4 connections स्वीकार करता है, तो operating systems अक्सर यह रूप दिखाते हैं। यह logs में इतना दिखता है कि इसे अजीब edge case मानना आगे चलकर भ्रम की गारंटी है।

दो उचित internal models हैं। हर authorization boundary के लिए एक चुनें और उसे UI में लिखें।

पहला model address families को अलग रखता है। ::ffff:192.0.2.7 kind ipv6 वाला 16-byte IPv6 address रहता है, जबकि 192.0.2.7 kind ipv4 वाला four-byte IPv4 address रहता है। उनकी तुलना कभी समान नहीं होती। जब approval किसी खास रूप में मांगे गए network connection को बताता है, तब यह अधिक सुरक्षित default है, क्योंकि यह परिवारों के बीच decision को चुपचाप फैलने से रोकता है।

दूसरा model सीमित peer-identity use case के लिए mapped addresses को IPv4 में project करता है। इस model में parser original family और embedded_ipv4 value दोनों रिकॉर्ड करता है। Comparison code जानबूझकर कहता है कि इस एक उद्देश्य के लिए mapped form अपने embedded IPv4 address के बराबर है। Audit record फिर भी raw form रखता है और बताता है कि comparison में projection का इस्तेमाल हुआ।

Accidental projection विफल होता है। कई standard libraries ऐसा convenience method देती हैं जो mapped address को IPv4 में बदल देता है और यह अंतर नहीं बताता कि वह किस रूप में आया था। यह connection logging के लिए उपयोगी है, मगर developer इसे approval token के लिए दोबारा इस्तेमाल करे तो खतरनाक है। तब 192.0.2.7 के लिए लिखा नियम बिना किसी निर्णय के ::ffff:192.0.2.7 को मंजूरी दे सकता है।

ऐसे test pairs इस्तेमाल करें जिनसे चुनाव साफ दिखे:

input A: 192.0.2.7
input B: ::ffff:192.0.2.7

strict endpoint comparison: different
explicit peer-identity projection: same IPv4 peer, if the product says so

Dotted tail वाली हर IPv6 string को mapped न मानें। Parser को पूरे prefix और IPv4 portion की position validate करनी चाहिए। RFC 4291 IPv4-mapped addresses को परिभाषित करता है और IPv6 text में IPv4-compatible notation की भी अनुमति देता है। आपके formatter को पर्याप्त typed information रखनी चाहिए ताकि हर dotted-tail address को एक ही चीज न कहा जाए।

Zone identifiers स्थानीय interface से जुड़े होते हैं

प्रॉम्प्ट से सीक्रेट दूर रखें
इसका एन्क्रिप्टेड वॉल्ट API और SSH कुंजियों को एजेंट कॉन्टेक्स्ट में नहीं, Mac ऐप के भीतर रखता है।

Zone identifier किसी अन्यथा अस्पष्ट scoped address को काम का स्थानीय destination बनाता है। fe80::1%en0 का मतलब interface en0 पर link-local address है। Zone के बिना, एक से अधिक network interfaces वाला host नहीं जान सकता कि कॉलर किस link की बात कर रहा है।

RFC 4007 इसे address में जोड़ी गई सजावट नहीं, scope zone concept कहता है। Interface name या index का अर्थ केवल उस host के लिए है जो इसे resolve करता है। किसी दूसरी machine पर en0 किसी अलग interface का नाम हो सकता है या हो ही नहीं सकता। इसलिए zone identifier portable approval target के लिए खराब विकल्प है।

सीधे local socket action के लिए zone तभी स्वीकार करें जब platform parser उसे validate करे और कार्रवाई उसी machine पर चले। अगर OS देता है तो comparison value के रूप में normalized numerical interface index स्टोर करें। Audit trail के लिए दिया गया interface name भी रख सकते हैं, मगर hardware और network configuration बदलने पर names बदल सकते हैं।

HTTP URI के लिए नियम अधिक सख्त हैं। RFC 6874 के अनुसार bracketed literal में zone identifier शुरू करने वाला percent sign %25 के रूप में encoded होता है। इसलिए URI में ऐसा रूप होता है:

http://[fe80::1%25en0]/status

URI parser को इसे सही चरण में decode करना चाहिए। Parse करने से पहले पूरे URL को percent-decode न करें, क्योंकि सामान्य decoder delimiters बदलकर कॉलर के दिए हुए URL से अलग URL बना सकता है। पहले URI parse करें, host literal निकालें, फिर उस component के लिए जरूरी scoped-literal rules लागू करें।

Agent-facing HTTP approval flows में अधिकतर scoped literals को अस्वीकार करना चाहिए और कॉलर को कारण बताना चाहिए: link-local addresses केवल किसी खास local interface के साथ ही अर्थ रखते हैं। Agent से stable DNS name, unscoped address या जानबूझकर configured local endpoint इस्तेमाल करने को कहना ऐसी मंजूरी बनाता है जिसे दूसरा व्यक्ति समझ सके। अपवाद केवल वहीं दें जहां product वास्तव में local network equipment के साथ काम करता हो और interface scope को साफ तौर पर दिखाता हो।

Host comparison कार्रवाई की मंजूरी से छोटा होता है

Address normalize करने से धोखे की एक सीमित श्रेणी ठीक होती है। इससे https://[2001:db8::9]/ और https://[2001:db8::9]:9443/delete बराबर नहीं हो जाते, और परिचित दिखने वाले host text से SSH destination सुरक्षित नहीं बनता।

Typed approval target में वे boundaries बनी रहनी चाहिए जिन्हें raw string छिपा देती है। HTTP के लिए आम तौर पर कम से कम scheme, host kind और bytes, default-port resolution के बाद port, method और path को उजागर करने वाला request description शामिल होना चाहिए। Headers और body digest decision का हिस्सा होंगे या नहीं, यह कार्रवाई पर निर्भर है। अगर एक bearer credential कई असंबंधित APIs को call कर सकता है, तो credential identity भी prompt में होनी चाहिए।

SSH के लिए network endpoint और remote command में अंतर करें। SSH connection खोलने की मंजूरी अपने आप sudo चलाने, deployment files बदलने या port forward करने की अनुमति नहीं बताती। अगर कोई tool एक connection के बाद कई operations कर सकता है, तो UI को बताना चाहिए कि session authorization किसे cover करता है और हर command का per-call record रखना चाहिए।

यहीं साफ data model का लाभ मिलता है। यह एक आकर्षक मगर गलत सलाह को रोकता है: canonical hosts को flat allowlist में डालें और काम पूरा समझ लें। Flat host lists लोकप्रिय हैं क्योंकि उन्हें समझाना आसान है। वे विफल होती हैं क्योंकि host कार्रवाई का केवल एक हिस्सा है और बाद का DNS answer, port, path या command असर बदल सकता है।

उपयोगी approval record ऐसा दिख सकता है:

transport: https
host_kind: ipv6
host_bytes: 20010db8000000000000000000000009
host_display: 2001:db8::9
scope_id: null
port: 8443
method: POST
path: /v1/releases
credential_ref: deploy-api
raw_authority: [2001:0db8::9]:8443

Raw authority अनुरोध का दस्तावेज है। Typed fields comparison चलाते हैं। Display field व्यक्ति को पढ़ने के लिए स्थिर वाक्य देता है। इनमें से किसी एक field को दूसरों का विकल्प बनाकर दोबारा इस्तेमाल न करें।

Rejection rules साधारण और सख्त होने चाहिए

जानें, अनुरोध कौन सा प्रोसेस कर रहा है
किसी रन को मंजूरी देने से पहले नया एजेंट प्रोसेस अपना कोड-साइनिंग प्राधिकरण दिखाता है।

जब input अपनी position के grammar में फिट न हो, parser को fail closed करना चाहिए। Error message मददगार हो सकता है, मगर system को कॉलर की मंशा का अनुमान लगाकर address ठीक नहीं करना चाहिए। लगभग-वैध input स्वीकार करने वाला normalizer दूसरा grammar बना देता है, जिसे security reviewers के लिए फिर से समझना कठिन होता है।

IP-literal request को अस्वीकार करें अगर उसमें इनमें से कोई दोष हो:

  • एक से ज्यादा :: compression marker हों या expansion के बाद बहुत ज्यादा fields हों
  • hexadecimal field में non-hexadecimal characters हों
  • IPv4 tail, IPv6 text syntax की स्वीकृत position के बाहर हो
  • bare address parser को brackets दिए गए हों, या URI authority में brackets न हों
  • ऐसे context में zone identifier हो जहां कार्रवाई local interface से bind नहीं हो सकती

ऐसे literal को भी अस्वीकार करें जिसे आपका URI parser और socket parser अलग तरह से समझते हों। यह सैद्धांतिक बारीकी नहीं है। समय के साथ अलग libraries ने percent encoding, असामान्य IPv4 forms और host parsing को लेकर अलग फैसले किए हैं। एक component text approve करे और दूसरा component किसी और जगह connection बनाए, तो authorization gap बनता है।

छोटा cross-layer test corpus बनाएं। हर case को उसी URI parser, host extractor, IP parser, formatter, comparator और transport builder से गुजारें जो production में इस्तेमाल होते हैं। Accepted input के लिए canonical display और वास्तविक socket destination, दोनों assert करें। Rejected input के लिए assert करें कि कोई transport object नहीं बनता।

Compact corpus में ::, ::1, fully expanded address, बराबर लंबाई के दो zero runs, port वाला bracketed URI literal, mapped IPv4 value, malformed dotted tail, scoped link-local literal और URI में encoded %25 zone शामिल होने चाहिए। अपने environment में agents ने जो भी input shapes वास्तव में बनाए हैं, उन्हें जोड़ें। वास्तविक approvals से बने regression tests parser tricks से कम चमकदार हैं, लेकिन अगली गलती पकड़ने की संभावना कहीं ज्यादा रखते हैं।

Approval card को normalization दिखाना चाहिए

हर चलाई गई कॉल का रिकॉर्ड रखें
Activity जर्नल हर कॉल दर्ज करता है और कार्रवाई के नतीजे के साथ सबूत सुरक्षित रखता है।

अगर card बदला हुआ हिस्सा छिपाता है, तो व्यक्ति endpoint का आकलन नहीं कर सकता। Canonical target को प्रमुखता से दिखाएं, फिर spelling अलग होने पर submitted spelling दिखाएं। Submitted as [2001:0DB8:0:0:0:0:0:9]:8443 जैसी शांत पंक्ति reviewer को fields मन में decode कराए बिना सबूत देती है।

Card को special forms भी साफ बताने चाहिए। Mapped address को सामान्य IPv6 literal की तरह दिखाने के बजाय IPv4-mapped IPv6 label दें। Scoped address पर interface name के साथ label लगाएं और कहें कि वह उसी interface के लिए local है। अगर action policy mapped address को IPv4 में project करती है, तो card में वह निर्णय लिखें। Chup equivalence से reviewers चौंकते हैं।

उच्च-परिणाम वाली calls के लिए व्यक्ति से केवल canonical host नहीं, पूरी कार्रवाई मंजूर कराएं। Compact presentation में भी जरूरी विवरण आ सकता है:

POST https://[2001:db8::9]:8443/v1/releases
Uses credential: deploy-api
Submitted host spelling: 2001:0DB8:0:0:0:0:0:9

Sallyport उसी जगह यह अलगाव निभाता है जहां इसकी जरूरत है: agent को कभी API या SSH secret नहीं मिलता, जबकि app कार्रवाई करता है और उसका परिणाम लौटाता है। इसका per-session authorization यह तय कर सकता है कि run किसने शुरू किया, और इसके per-call controls संवेदनशील actions को दिखाई देते रहने देते हैं, उन्हें पहले की मंजूरी का blank check नहीं मानते।

Audit records को raw text और normalized meaning, दोनों चाहिए

Incident review में दो ऐसे जवाब चाहिए जिनमें सिर्फ एक representation बचाने पर अक्सर टकराव होता है: agent ने वास्तव में क्या भेजा और transport ने किस destination का उपयोग किया? दोनों सहेजें। फिर साफ बताएं कि decision किस value से लिया गया।

Audit event में raw input, parsed host kind, canonical display form, unambiguous encoding में address bytes, मौजूद होने पर scope identity और approval में शामिल सभी action fields होने चाहिए। Serialization के बाद event hash करना तभी उपयोगी है जब serialization की स्थिर परिभाषा हो। वरना formatter बदलने से एक ही semantic event अलग records बना सकता है।

Display form निकालने के बाद noncanonical input मिटाएं नहीं। वह किसी buggy client, bypass की कोशिश या किसी हानिरहित library quirk का संकेत हो सकता है, जो बाद में incident समझाने में मदद करे। उसे evidence की तरह रखें, मगर search dashboards उसे उसी endpoint की भ्रामक दूसरी identity न बनाने दें।

Sallyport के Activity journal और Sessions journal एक encrypted, hash-chained audit log से बनते हैं, और sp audit verify उस chain को ciphertext पर offline जांचता है। यह संरचना खास तौर पर तब उपयोगी है जब reviewer को असामान्य spelling और अलग executed action में फर्क करना हो।

पूरी approval layer को नए सिरे से डिजाइन करने से पहले एक test से शुरू करें: एक ही target को fully expanded और RFC 5952 form में submit करें। अगर आपका system अलग approval identities, अलग audit search results या अलग allow decisions देता है, तो parser boundary अभी भी गलत जगह है।

सामान्य प्रश्न

क्या दो IPv6 स्ट्रिंग एक ही पते को संदर्भित कर सकती हैं?

नहीं। IPv6 में शून्य संपीड़न, शुरुआती शून्य छोड़ना और मिश्रित IPv6 व IPv4 नोटेशन मान्य हैं, इसलिए कई स्ट्रिंग एक ही 128-बिट पते को दर्शा सकती हैं। कॉलर के दिए टेक्स्ट की नहीं, पार्स किए गए address bytes और संबंधित scope data की तुलना करें।

URLs में IPv6 पते को brackets की जरूरत क्यों होती है?

URI authority में IPv6 literal होने पर brackets लगाएं, जैसे https://[2001:db8::7]:8443/। brackets को पते का हिस्सा बनाकर न रखें, वे URI व्याकरण का हिस्सा हैं।

IPv4-mapped IPv6 address क्या होता है?

::ffff:192.0.2.7 एक IPv4-mapped IPv6 address है। IPv4 peer के IPv6 socket से आने पर कई APIs इसे बनाती हैं, इसलिए approval system को साफ तौर पर तय करना चाहिए कि इसकी तुलना उसी IPv6 मान से होगी या उसमें समाए IPv4 पते से।

क्या HTTP approval target में zone identifier की अनुमति देनी चाहिए?

आमतौर पर नहीं। Zone identifier किसी link-local address को interface scope देता है, इसलिए उसका अर्थ केवल उस मशीन पर होता है जो उस interface को जानती है। Remote HTTP approvals के लिए DNS नाम या बिना scope वाला routable address मांगें।

Canonical IPv6 text format क्या है?

हां। RFC 5952 lowercase hexadecimal, शुरुआती शून्य हटाने और zero fields की सबसे लंबी श्रृंखला को :: से संपीड़ित करने की सलाह देता है। बराबरी होने पर पहली श्रृंखला चुनें। Canonical text लोगों को targets की समीक्षा करने में मदद करता है, मगर byte-level comparison की जगह नहीं लेता।

क्या IPv6 host मंजूर करने से उसके हर port की मंजूरी मिल जाती है?

नहीं। Bracket वाला IPv6 literal केवल URI syntax में host को दिखाने का तरीका है। Port भी मायने रखता है और एजेंट जिस कार्रवाई की मंजूरी मांग रहा है, उसमें scheme, path, query, method और credential identity भी अहम हो सकते हैं।

अगर approval target में hostname हो तो क्या करना चाहिए?

IP literal parser के लिए उसे अस्वीकार करें, फिर यदि आपका product names को समर्थन देता है तो उसे अलग से hostname की तरह संभालें। Hostname को जबरन IPv6 normalization से गुजारने पर अस्पष्ट और अक्सर असुरक्षित fallback व्यवहार पैदा होता है।

क्या मुझे मूल IPv6 address text स्टोर करना चाहिए?

ऑडिट ट्रेल के लिए मूल अनुरोध सुरक्षित रखें, मगर canonical display value दिखाएं और typed internal value की तुलना करें। ये तीनों रूप अलग सवालों का जवाब देते हैं: क्या आया, व्यक्ति ने क्या देखा और system ने किसे मंजूरी दी।

क्या मैं malformed IPv6 addresses को normalize कर सकता हूं?

नहीं। Parser को malformed brackets, कई :: markers, अमान्य hex groups, गलत जगह IPv4 tail और ऐसे zone identifier को अस्वीकार करना चाहिए जहां आसपास का व्याकरण उसे मना करता हो। Parsers में मतभेद को विफलता मानें, अनुमान लगाने का कारण नहीं।

Approval system को DNS names और IPv6 कैसे संभालने चाहिए?

DNS को hostname के अनुरूप नियमों के तहत अलग से resolve करें, फिर logging और comparison के लिए हर लौटे पते को normalize करें। Hostname को चुपचाप एक मंजूर literal में न बदलें, क्योंकि बाद में मिलने वाला DNS उत्तर उसी नाम को दूसरी जगह ले जा सकता है।

Sallyport

Sallyport आपके AI एजेंट के लिए API कॉल और SSH कमांड चलाता है। कुंजियाँ आपके Mac पर एक लोकल वॉल्ट में रहती हैं; आप हर रन को स्वीकृत करते हैं और हर क्रिया एक सीलबंद जर्नल में दर्ज होती है।

© 2026 Sallyport · Apache-2.0 के तहत ओपन सोर्स · Oleg Sotnikov