Search code examples
unity-game-engineuwpfiddlercharles-proxyil2cpp

How to get Fiddler or Charles to capture traffic from Unity 2018 IL2CPP apps


I have built apps with Unity 5 and with Unity 2017, and am able to use Fiddler or Charles to capture network traffic successfully. However, When I build a Unity 2018 app using IL2CPP (the other apps were built with .Net), the app works (successfully sending network traffic), but the app seems to somehow bypass the Fiddler (or Charles) proxy. That is, Fiddler and Charles are unable to show the network traffic from the Unity 2018 IL2CPP app, even though it can show traffic from Unity 5 and Unity 2017 apps.

Note that everything works with Unity 5 and Unity 2017, and, that the SSL settings, etc. have been setup previously. Also, I have used the Fiddler "WinConfig" to EnableLoopback for the Unity 2018 app.

My question is: What do I need to do to get a Unity 2018 IL2CPP app to show traffic in Fiddler or Charles?

Update: Here is some sample code that shows that HttpClient requests don't go through the proxy, but other (Unity) webrequests do go through the proxy:

public class RequestTest : MonoBehaviour
{
    public UnityEngine.UI.Text text;

    void Update()
    {
        if (Input.GetKeyUp(KeyCode.P))
        {
            StartCoroutine(yieldPing());
        }
        if (Input.GetKeyUp(KeyCode.O))
        {
            asyncPing();
        }
    }

    private IEnumerator yieldPing()
    {
        Debug.Log("This request shows up in Fiddler");
        text.text = "UWR in Coroutine";
        using (UnityWebRequest uwr = UnityWebRequest.Get("https://www.google.com/"))
        {
            yield return uwr.SendWebRequest();
        }
    }

    private async void asyncPing()
    {
        await awaitPing();
    }

    private async System.Threading.Tasks.Task<bool> awaitPing()
    {
        Debug.Log("This request also shows up in Fiddler");
        UnityWebRequest uwr = UnityWebRequest.Get("https://www.google.com/");
        text.text = "UWR in async await";
        uwr.SendWebRequest().completed += delegate
        {
            uwr.Dispose();
        };

        Debug.Log("This request does NOT show up in Fiddler???");
        text.text += "\nHttpClient in async await";
        using (System.Net.Http.HttpClient httpClient = new System.Net.Http.HttpClient())
        {
            using (System.Net.Http.HttpRequestMessage httpRequest = new System.Net.Http.HttpRequestMessage())
            {
                httpRequest.RequestUri = new System.Uri("http://www.youtube.com/");
                httpRequest.Method = System.Net.Http.HttpMethod.Get;
                using (System.Net.Http.HttpResponseMessage httpResponse = await httpClient.SendAsync(httpRequest, System.Net.Http.HttpCompletionOption.ResponseHeadersRead))
                {
                    var responseCode = (int)httpResponse.StatusCode;
                    // We will get a 304 if the content has not been modified
                    // If there is new, good content, then we will get a 200
                    return (responseCode == 200);
                }
            }
        }
    }
}

Here are the Unity Player Settings: Here are the Unity Player Settings


Solution

  • Unity has acknowledged that this is a problem:

    https://fogbugz.unity3d.com/default.asp?1222589_u6qsndet3umnp50u

    https://issuetracker.unity3d.com/issues/httpclient-ignores-windows-proxy

    It appears that during the "IL2CPP" code generation process, the generated code changes the HttpClient to not use the local proxy.

    The code below was copied from here, and seems to overcome the Unity IL2CPP bug:

     // might be overly complicated, there is an option to wrap the existing proxy here...
    class myWebProxy : System.Net.IWebProxy
    {
        private System.Net.IWebProxy wrappedProxy;
        private System.Net.ICredentials creds;
        private void init()
        {
            wrappedProxy = null;
            creds = CredentialCache.DefaultCredentials;
        }
        public myWebProxy()
        {
            init();
        }
    
        public myWebProxy(System.Net.IWebProxy theWrappedProxy)
        {
            init();
            wrappedProxy = theWrappedProxy;
        }
        public System.Net.ICredentials Credentials
        {
            get
            {
                if (wrappedProxy != null)
                {
                    return wrappedProxy.Credentials;
                }
                else
                {
                    return creds;
                }
            }
            set
            {
                if (wrappedProxy != null)
                {
                    wrappedProxy.Credentials = value;
                }
                else
                {
                    creds = value;
                }
    
            }
        }
    
        public Uri GetProxy(Uri destination)
        {
            if (wrappedProxy != null /* todo or Uri == certain Uri */)
            {
                return wrappedProxy.GetProxy(destination);
            }
            else
            {
                // hardcoded proxy here..
                return new Uri("http://seeplusplus:8080");
            }
        }
    
        public bool IsBypassed(Uri host)
        {
            if (wrappedProxy != null)
            {
                return wrappedProxy.IsBypassed(host);
            }
            else
            {
                return false;
            }
    
        }
    }
    
    
    // in your code use your new proxy
                HttpClientHandler aHandler = new HttpClientHandler();
    // use your proxy!
                aHandler.Proxy = new myWebProxy();
                HttpClient client = new HttpClient(aHandler);