|
1 | 1 | defmodule ExICE.Priv.Gatherer do
|
2 | 2 | @moduledoc false
|
3 | 3 |
|
| 4 | + alias ExICE.ICEAgent |
4 | 5 | alias ExICE.Priv.{Candidate, Transport, Utils}
|
5 | 6 | alias ExSTUN.Message
|
6 | 7 | alias ExSTUN.Message.Type
|
@@ -139,6 +140,104 @@ defmodule ExICE.Priv.Gatherer do
|
139 | 140 | end
|
140 | 141 | end
|
141 | 142 |
|
| 143 | + @spec fabricate_srflx_candidates([Candidate.Host.t()], ICEAgent.host_to_srflx_ip_mapper(), %{ |
| 144 | + :inet.ip_address() => non_neg_integer() |
| 145 | + }) :: [Candidate.Srflx.t()] |
| 146 | + def fabricate_srflx_candidates(_host_cands, nil, _local_preferences) do |
| 147 | + [] |
| 148 | + end |
| 149 | + |
| 150 | + def fabricate_srflx_candidates(host_cands, host_to_srflx_ip_mapper, local_preferences) do |
| 151 | + do_fabricate_srflx_candidates( |
| 152 | + host_cands, |
| 153 | + host_to_srflx_ip_mapper, |
| 154 | + local_preferences, |
| 155 | + [], |
| 156 | + [] |
| 157 | + ) |
| 158 | + end |
| 159 | + |
| 160 | + defp do_fabricate_srflx_candidates( |
| 161 | + [], |
| 162 | + _host_to_srflx_ip_mapper, |
| 163 | + _local_preferences, |
| 164 | + srflx_cands, |
| 165 | + _external_ips |
| 166 | + ) do |
| 167 | + srflx_cands |
| 168 | + end |
| 169 | + |
| 170 | + defp do_fabricate_srflx_candidates( |
| 171 | + [host_cand | rest], |
| 172 | + host_to_srflx_ip_mapper, |
| 173 | + local_preferences, |
| 174 | + srflx_cands, |
| 175 | + external_ips |
| 176 | + ) do |
| 177 | + external_ip = host_to_srflx_ip_mapper.(host_cand.base.address) |
| 178 | + |
| 179 | + if valid_external_ip?(external_ip, host_cand.base.address, external_ips) do |
| 180 | + priority = |
| 181 | + Candidate.priority!(local_preferences, host_cand.base.address, :srflx) |
| 182 | + |
| 183 | + cand = |
| 184 | + Candidate.Srflx.new( |
| 185 | + address: external_ip, |
| 186 | + port: host_cand.base.port, |
| 187 | + base_address: host_cand.base.address, |
| 188 | + base_port: host_cand.base.port, |
| 189 | + priority: priority, |
| 190 | + transport_module: host_cand.base.transport_module, |
| 191 | + socket: host_cand.base.socket |
| 192 | + ) |
| 193 | + |
| 194 | + Logger.debug("New srflx candidate from NAT mapping: #{inspect(cand)}") |
| 195 | + |
| 196 | + do_fabricate_srflx_candidates( |
| 197 | + rest, |
| 198 | + host_to_srflx_ip_mapper, |
| 199 | + local_preferences, |
| 200 | + [cand | srflx_cands], |
| 201 | + [external_ip | external_ips] |
| 202 | + ) |
| 203 | + else |
| 204 | + do_fabricate_srflx_candidates( |
| 205 | + rest, |
| 206 | + host_to_srflx_ip_mapper, |
| 207 | + local_preferences, |
| 208 | + srflx_cands, |
| 209 | + external_ips |
| 210 | + ) |
| 211 | + end |
| 212 | + end |
| 213 | + |
| 214 | + defp valid_external_ip?(external_ip, host_ip, external_ips) do |
| 215 | + same_type? = :inet.is_ipv4_address(external_ip) == :inet.is_ipv4_address(host_ip) |
| 216 | + |
| 217 | + cond do |
| 218 | + host_ip == external_ip -> |
| 219 | + log_warning(host_ip, external_ip, "external IP is the same as local IP") |
| 220 | + false |
| 221 | + |
| 222 | + not :inet.is_ip_address(external_ip) or not same_type? -> |
| 223 | + log_warning(host_ip, external_ip, "not valid IP address") |
| 224 | + false |
| 225 | + |
| 226 | + external_ip in external_ips -> |
| 227 | + log_warning(host_ip, external_ip, "address already in use") |
| 228 | + false |
| 229 | + |
| 230 | + true -> |
| 231 | + true |
| 232 | + end |
| 233 | + end |
| 234 | + |
| 235 | + defp log_warning(host_ip, external_ip, reason), |
| 236 | + do: |
| 237 | + Logger.warning( |
| 238 | + "Ignoring NAT mapping: #{inspect(host_ip)} to #{inspect(external_ip)}, #{inspect(reason)}" |
| 239 | + ) |
| 240 | + |
142 | 241 | defp loopback_if?({_int_name, int}) do
|
143 | 242 | :loopback in int[:flags]
|
144 | 243 | end
|
|
0 commit comments