1-- Prosody IM 2-- Copyright (C) 2011-2013 Florian Zeitz 3-- 4-- This project is MIT/X11 licensed. Please see the 5-- COPYING file in the source package for more information. 6-- 7 8-- This is used to sort destination addresses by preference 9-- during S2S connections. 10-- We can't hand this off to getaddrinfo, since it blocks 11 12local ip_commonPrefixLength = require"util.ip".commonPrefixLength 13 14local function commonPrefixLength(ipA, ipB) 15 local len = ip_commonPrefixLength(ipA, ipB); 16 return len < 64 and len or 64; 17end 18 19local function t_sort(t, comp) 20 for i = 1, (#t - 1) do 21 for j = (i + 1), #t do 22 local a, b = t[i], t[j]; 23 if not comp(a,b) then 24 t[i], t[j] = b, a; 25 end 26 end 27 end 28end 29 30local function source(dest, candidates) 31 local function comp(ipA, ipB) 32 -- Rule 1: Prefer same address 33 if dest == ipA then 34 return true; 35 elseif dest == ipB then 36 return false; 37 end 38 39 -- Rule 2: Prefer appropriate scope 40 if ipA.scope < ipB.scope then 41 if ipA.scope < dest.scope then 42 return false; 43 else 44 return true; 45 end 46 elseif ipA.scope > ipB.scope then 47 if ipB.scope < dest.scope then 48 return true; 49 else 50 return false; 51 end 52 end 53 54 -- Rule 3: Avoid deprecated addresses 55 -- XXX: No way to determine this 56 -- Rule 4: Prefer home addresses 57 -- XXX: Mobility Address related, no way to determine this 58 -- Rule 5: Prefer outgoing interface 59 -- XXX: Interface to address relation. No way to determine this 60 -- Rule 6: Prefer matching label 61 if ipA.label == dest.label and ipB.label ~= dest.label then 62 return true; 63 elseif ipB.label == dest.label and ipA.label ~= dest.label then 64 return false; 65 end 66 67 -- Rule 7: Prefer temporary addresses (over public ones) 68 -- XXX: No way to determine this 69 -- Rule 8: Use longest matching prefix 70 if commonPrefixLength(ipA, dest) > commonPrefixLength(ipB, dest) then 71 return true; 72 else 73 return false; 74 end 75 end 76 77 t_sort(candidates, comp); 78 return candidates[1]; 79end 80 81local function destination(candidates, sources) 82 local sourceAddrs = {}; 83 local function comp(ipA, ipB) 84 local ipAsource = sourceAddrs[ipA]; 85 local ipBsource = sourceAddrs[ipB]; 86 -- Rule 1: Avoid unusable destinations 87 -- XXX: No such information 88 -- Rule 2: Prefer matching scope 89 if ipA.scope == ipAsource.scope and ipB.scope ~= ipBsource.scope then 90 return true; 91 elseif ipA.scope ~= ipAsource.scope and ipB.scope == ipBsource.scope then 92 return false; 93 end 94 95 -- Rule 3: Avoid deprecated addresses 96 -- XXX: No way to determine this 97 -- Rule 4: Prefer home addresses 98 -- XXX: Mobility Address related, no way to determine this 99 -- Rule 5: Prefer matching label 100 if ipAsource.label == ipA.label and ipBsource.label ~= ipB.label then 101 return true; 102 elseif ipBsource.label == ipB.label and ipAsource.label ~= ipA.label then 103 return false; 104 end 105 106 -- Rule 6: Prefer higher precedence 107 if ipA.precedence > ipB.precedence then 108 return true; 109 elseif ipA.precedence < ipB.precedence then 110 return false; 111 end 112 113 -- Rule 7: Prefer native transport 114 -- XXX: No way to determine this 115 -- Rule 8: Prefer smaller scope 116 if ipA.scope < ipB.scope then 117 return true; 118 elseif ipA.scope > ipB.scope then 119 return false; 120 end 121 122 -- Rule 9: Use longest matching prefix 123 if commonPrefixLength(ipA, ipAsource) > commonPrefixLength(ipB, ipBsource) then 124 return true; 125 elseif commonPrefixLength(ipA, ipAsource) < commonPrefixLength(ipB, ipBsource) then 126 return false; 127 end 128 129 -- Rule 10: Otherwise, leave order unchanged 130 return true; 131 end 132 for _, ip in ipairs(candidates) do 133 sourceAddrs[ip] = source(ip, sources); 134 end 135 136 t_sort(candidates, comp); 137 return candidates; 138end 139 140return {source = source, 141 destination = destination}; 142